2.7 벚꽃팩 CON 수치에 따른 HP상승 린클화 아난 선택의 다양성 개선 고민
컨텐츠 정보
- 495 조회
- 5 댓글
- 목록
본문
..아예 린클 처럼은 당연히 안되고, 제 능력상 기능 구현 못하는 것도 있고..
일단 아래가 기본값인데
2.70 벚꽃팩\src\l1j\server\server\utils\CalcStat.java
1. baseCON 보너스
CON 15 이하: 보너스 0
CON 16 이상: CON 1당 +1씩 증가 (CON 16=+1, 17=+2, 18=+3, ..., 25=+10)
이 보너스는 15를 초과하는 수치만큼만 추가로 더해집니다.
2. 클래스별 기본 성장 (모든 캐릭터 공통)
이 부분은 CON 수치와 상관없이 레벨업 시마다 모든 캐릭터가 획득합니다.
군주/엘프/다크엘프: 5 (기본값) + 0~5 (랜덤값)
기사: 6 (기본값) + 0~6 (랜덤값)
마법사: 3 (기본값) + 0~3 (랜덤값)
아래처럼 바꿀까 생각했습니다만..
콘15 레벨업 할때마다 50%퍼 확률로 0또는 1 증가, 25%퍼 확률로 추가 보너스 2증가
콘16 콘1당 HP 1씩증가에 따라 기본 고정 보너스 1 + 추가 보너스 1~3
콘17 콘1당 HP 1씩증가에 따라 기본 고정 보너스 2+ 추가 보너스 2~4
콘18 콘1당 HP 1씩증가에 따라 기본 고정 보너스 3+ 추가 보너스 3~5
(..중간생략..)
콘25 고정 보너스 10 + 추가 보너스 10~12
이렇게 바꿔도 결국 차이는 발생하네요.
차이를 없애면 다들 콘15미만 할거고..;;
-
등록일 2026.08.24
-
등록일 2026.07.27
-
등록일 2026.07.04DLL인젝션 점이라도 하나 찍어보기댓글 3
-
등록일 2026.06.29
관련자료
댓글 5
개인구축러님의 댓글
이렇게 하기로 했습니다
CON 15 이하 유저는 매 레벨업마다 "0 아니면 1"이라는 기초 보너스를 획득하고,
추가로 "가중치 보너스(1~10)"를 받습니다.
1 확률 50
2 45
3 40
4 35
5 30
6 25
7 20
8 15
9 10
10 5
(가중치 랜덤 계산 방식 총합100% 확률방식 아님)
CON 16 이상 유저는 "확정 보너스(CON-15)"를 받고, 추가로 "가중치 보너스(1~10)"를 받습니다.
2.70 벚꽃팩\src\l1j\server\server\utils\CalcStat.java
public static short calcStatHp(int charType, int baseMaxHp, byte baseCon) {
short randomhp = 0;
// 1. 기존 CON 보너스 로직 유지
if (baseCon > 15) {
randomhp = (short) (baseCon - 15);
}
// 2. 가중치 기반 추가 보너스 (1~10)
// 숫자가 낮을수록 나올 확률이 높고, 숫자가 클수록 희귀하게 설정
int[] weights = {50, 45, 40, 35, 30, 25, 20, 15, 10, 5};
int totalWeight = 0;
for (int w : weights) totalWeight += w;
int roll = rnd.nextInt(totalWeight);
int sum = 0;
int bonus = 1;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (roll < sum) {
bonus = (i + 1);
break;
}
}
randomhp += (short) bonus;
// 3. 기존 클래스별 랜덤 성장 로직
if (charType == 0) { // 프린스
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.PRINCE_MAX_HP) {
randomhp = (short) (Config.PRINCE_MAX_HP - baseMaxHp);
}
} else if (charType == 1) { // 나이트
randomhp += (short) (6 + rnd.nextInt(7));
if (baseMaxHp + randomhp > Config.KNIGHT_MAX_HP) {
randomhp = (short) (Config.KNIGHT_MAX_HP - baseMaxHp);
}
} else if (charType == 2) { // 에르프
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.ELF_MAX_HP) {
randomhp = (short) (Config.ELF_MAX_HP - baseMaxHp);
}
} else if (charType == 3) { // 위저드
randomhp += (short) (3 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.WIZARD_MAX_HP) {
randomhp = (short) (Config.WIZARD_MAX_HP - baseMaxHp);
}
} else if (charType == 4) { // 다크 에르프
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.DARKELF_MAX_HP) {
randomhp = (short) (Config.DARKELF_MAX_HP - baseMaxHp);
}
}
if (randomhp < 0) {
randomhp = 0;
}
return randomhp;
}
/**
* 각 클래스의 LVUP시의 MP상승치를 돌려준다
*
* @param charType
* @param baseMaxMp
* @param baseWis
* @return MP상승치
*/
CON 15 이하 유저는 매 레벨업마다 "0 아니면 1"이라는 기초 보너스를 획득하고,
추가로 "가중치 보너스(1~10)"를 받습니다.
1 확률 50
2 45
3 40
4 35
5 30
6 25
7 20
8 15
9 10
10 5
(가중치 랜덤 계산 방식 총합100% 확률방식 아님)
CON 16 이상 유저는 "확정 보너스(CON-15)"를 받고, 추가로 "가중치 보너스(1~10)"를 받습니다.
2.70 벚꽃팩\src\l1j\server\server\utils\CalcStat.java
public static short calcStatHp(int charType, int baseMaxHp, byte baseCon) {
short randomhp = 0;
// 1. 기존 CON 보너스 로직 유지
if (baseCon > 15) {
randomhp = (short) (baseCon - 15);
}
// 2. 가중치 기반 추가 보너스 (1~10)
// 숫자가 낮을수록 나올 확률이 높고, 숫자가 클수록 희귀하게 설정
int[] weights = {50, 45, 40, 35, 30, 25, 20, 15, 10, 5};
int totalWeight = 0;
for (int w : weights) totalWeight += w;
int roll = rnd.nextInt(totalWeight);
int sum = 0;
int bonus = 1;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (roll < sum) {
bonus = (i + 1);
break;
}
}
randomhp += (short) bonus;
// 3. 기존 클래스별 랜덤 성장 로직
if (charType == 0) { // 프린스
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.PRINCE_MAX_HP) {
randomhp = (short) (Config.PRINCE_MAX_HP - baseMaxHp);
}
} else if (charType == 1) { // 나이트
randomhp += (short) (6 + rnd.nextInt(7));
if (baseMaxHp + randomhp > Config.KNIGHT_MAX_HP) {
randomhp = (short) (Config.KNIGHT_MAX_HP - baseMaxHp);
}
} else if (charType == 2) { // 에르프
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.ELF_MAX_HP) {
randomhp = (short) (Config.ELF_MAX_HP - baseMaxHp);
}
} else if (charType == 3) { // 위저드
randomhp += (short) (3 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.WIZARD_MAX_HP) {
randomhp = (short) (Config.WIZARD_MAX_HP - baseMaxHp);
}
} else if (charType == 4) { // 다크 에르프
randomhp += (short) (5 + rnd.nextInt(6));
if (baseMaxHp + randomhp > Config.DARKELF_MAX_HP) {
randomhp = (short) (Config.DARKELF_MAX_HP - baseMaxHp);
}
}
if (randomhp < 0) {
randomhp = 0;
}
return randomhp;
}
/**
* 각 클래스의 LVUP시의 MP상승치를 돌려준다
*
* @param charType
* @param baseMaxMp
* @param baseWis
* @return MP상승치
*/
개인구축러님의 댓글
[클래스별 HP 보너스]
군주: 5 + 0~3 = 최종 상승 HP 5~8
기사: 6 + 0~4 = 최종 상승 HP 6~10
엘프: 5 + 0~3 = 최종 상승 HP 5~8
마법사: 3 + 0~2 = 최종 상승 HP 3~5
다크엘프: 5 + 0~3 = 최종 상승 HP 5~8
CON 15 미만 유저
0~1 + 클래스별 HP 보너스 + 1~10 가중치 랜덤
CON 15 이상 유저
결과: +3 + 클래스별 HP 보너스 + 1~10 가중치 랜덤
2.70 벚꽃팩 원본 베이스에
src\l1j\server\server\utils\CalcStat.java에 아래 코드 전체 통으로 덮어씌운다음
컴파일 하시고 테스트 해보시면 됩니다.
package l1j.server.server.utils;
import java.util.Random;
import l1j.server.Config;
public class CalcStat {
private static Random rnd = new Random();
private CalcStat() {
}
/**
* AC보너스를 돌려준다
*
* @param level
* @param dex
* @return acBonus
*
*/
public static int calcAc(int level, int dex) {
int acBonus = 10;
if (dex <= 9) {
acBonus -= level / 8;
} else if (dex >= 10 && dex <= 12) {
acBonus -= level / 7;
} else if (dex >= 13 && dex <= 15) {
acBonus -= level / 6;
} else if (dex >= 16 && dex <= 17) {
acBonus -= level / 5;
} else if (dex >= 18) {
acBonus -= level / 4;
}
return acBonus;
}
/**
* 인수의 WIS에 대응하는 MR보너스를 돌려준다
*
* @param wis
* @return mrBonus
*/
public static int calcStatMr(int wis) {
int mrBonus = 0;
if (wis <= 14) {
mrBonus = 0;
} else if (wis >= 15 && wis <= 16) {
mrBonus = 3;
} else if (wis == 17) {
mrBonus = 6;
} else if (wis == 18) {
mrBonus = 10;
} else if (wis == 19) {
mrBonus = 15;
} else if (wis == 20) {
mrBonus = 21;
} else if (wis == 21) {
mrBonus = 28;
} else if (wis == 22) {
mrBonus = 37;
} else if (wis == 23) {
mrBonus = 47;
} else if (wis == 24) {
mrBonus = 50;
} else {
mrBonus = 50;
}
return mrBonus;
}
public static int calcDiffMr(int wis, int diff) {
return calcStatMr(wis + diff) - calcStatMr(wis);
}
/**
* 각 클래스의 LVUP시의 HP상승치를 돌려준다
*
* @param charType
* @param baseMaxHp
* @param baseCon
* @return HP상승치
*/
public static short calcStatHp(int charType, int baseMaxHp, byte baseCon) {
short randomhp = 0;
// 1. CON 보너스 로직 (확정 보너스 + 15 이하일 때 50% 확률)
if (baseCon > 15) {
// CON 16 이상: 확정 보너스
randomhp = (short) (baseCon - 15);
} else {
// CON 15 이하: 50% 확률로 0 또는 1 추가
if (rnd.nextBoolean()) {
randomhp = 1;
} else {
randomhp = 0;
}
}
// 2. 가중치 기반 추가 보너스 (1~10)
// 숫자가 낮을수록 나올 확률이 높고, 숫자가 클수록 희귀하게 설정
int[] weights = {55, 50, 45, 40, 32, 20, 15, 10, 5, 3};
int totalWeight = 0;
for (int w : weights) totalWeight += w;
int roll = rnd.nextInt(totalWeight);
int sum = 0;
int bonus = 1;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (roll < sum) {
bonus = (i + 1);
break;
}
}
randomhp += (short) bonus;
// 3. 기존 클래스별 랜덤 성장 로직
if (charType == 0) { // 프린스
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.PRINCE_MAX_HP) {
randomhp = (short) (Config.PRINCE_MAX_HP - baseMaxHp);
}
} else if (charType == 1) { // 나이트
randomhp += (short) (6 + rnd.nextInt(5));
if (baseMaxHp + randomhp > Config.KNIGHT_MAX_HP) {
randomhp = (short) (Config.KNIGHT_MAX_HP - baseMaxHp);
}
} else if (charType == 2) { // 에르프
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.ELF_MAX_HP) {
randomhp = (short) (Config.ELF_MAX_HP - baseMaxHp);
}
} else if (charType == 3) { // 위저드
randomhp += (short) (3 + rnd.nextInt(3));
if (baseMaxHp + randomhp > Config.WIZARD_MAX_HP) {
randomhp = (short) (Config.WIZARD_MAX_HP - baseMaxHp);
}
} else if (charType == 4) { // 다크 에르프
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.DARKELF_MAX_HP) {
randomhp = (short) (Config.DARKELF_MAX_HP - baseMaxHp);
}
}
if (randomhp < 0) {
randomhp = 0;
}
return randomhp;
}
/**
* 각 클래스의 LVUP시의 MP상승치를 돌려준다
*
* @param charType
* @param baseMaxMp
* @param baseWis
* @return MP상승치
*/
public static short calcStatMp(int charType, int baseMaxMp, byte baseWis) {
int randommp = 0;
int seed = 0;
if (baseWis <= 9) {
seed = -2;
} else if (baseWis == 10 || baseWis == 11) {
seed = -1;
} else if (baseWis >= 12 && baseWis <= 14) {
seed = 0;
} else if (baseWis >= 15 && baseWis <= 17) {
seed = 2;
} else if (baseWis == 18 || baseWis == 19) {
seed = 3;
} else if (baseWis == 20) {
seed = 4;
} else if (baseWis >= 21 && baseWis <= 23) {
seed = 5;
} else if (baseWis == 24) {
seed = 6;
} else if (baseWis == 25) {
seed = 7;
}
randommp = 2 + rnd.nextInt(3 + seed % 2 + (seed / 6) * 2) + seed / 2
- seed / 6;
if (charType == 0) { // 프린스
if (baseMaxMp + randommp > Config.PRINCE_MAX_MP) {
randommp = Config.PRINCE_MAX_MP - baseMaxMp;
}
} else if (charType == 1) { // 나이트
if (baseWis == 9) {
randommp -= 1;
} else {
randommp = (int) (1.0 * randommp / 2 + 0.5);
}
if (baseMaxMp + randommp > Config.KNIGHT_MAX_MP) {
randommp = Config.KNIGHT_MAX_MP - baseMaxMp;
}
} else if (charType == 2) { // 에르프
randommp = (int) (randommp * 1.5);
if (baseMaxMp + randommp > Config.ELF_MAX_MP) {
randommp = Config.ELF_MAX_MP - baseMaxMp;
}
} else if (charType == 3) { // 위저드
randommp *= 2;
if (baseMaxMp + randommp > Config.WIZARD_MAX_MP) {
randommp = Config.WIZARD_MAX_MP - baseMaxMp;
}
} else if (charType == 4) { // 다크 에르프
randommp = (int) (randommp * 1.5);
if (baseMaxMp + randommp > Config.DARKELF_MAX_MP) {
randommp = Config.DARKELF_MAX_MP - baseMaxMp;
}
}
if (randommp < 0) {
randommp = 0;
}
return (short) randommp;
}
}
군주: 5 + 0~3 = 최종 상승 HP 5~8
기사: 6 + 0~4 = 최종 상승 HP 6~10
엘프: 5 + 0~3 = 최종 상승 HP 5~8
마법사: 3 + 0~2 = 최종 상승 HP 3~5
다크엘프: 5 + 0~3 = 최종 상승 HP 5~8
CON 15 미만 유저
0~1 + 클래스별 HP 보너스 + 1~10 가중치 랜덤
CON 15 이상 유저
결과: +3 + 클래스별 HP 보너스 + 1~10 가중치 랜덤
2.70 벚꽃팩 원본 베이스에
src\l1j\server\server\utils\CalcStat.java에 아래 코드 전체 통으로 덮어씌운다음
컴파일 하시고 테스트 해보시면 됩니다.
package l1j.server.server.utils;
import java.util.Random;
import l1j.server.Config;
public class CalcStat {
private static Random rnd = new Random();
private CalcStat() {
}
/**
* AC보너스를 돌려준다
*
* @param level
* @param dex
* @return acBonus
*
*/
public static int calcAc(int level, int dex) {
int acBonus = 10;
if (dex <= 9) {
acBonus -= level / 8;
} else if (dex >= 10 && dex <= 12) {
acBonus -= level / 7;
} else if (dex >= 13 && dex <= 15) {
acBonus -= level / 6;
} else if (dex >= 16 && dex <= 17) {
acBonus -= level / 5;
} else if (dex >= 18) {
acBonus -= level / 4;
}
return acBonus;
}
/**
* 인수의 WIS에 대응하는 MR보너스를 돌려준다
*
* @param wis
* @return mrBonus
*/
public static int calcStatMr(int wis) {
int mrBonus = 0;
if (wis <= 14) {
mrBonus = 0;
} else if (wis >= 15 && wis <= 16) {
mrBonus = 3;
} else if (wis == 17) {
mrBonus = 6;
} else if (wis == 18) {
mrBonus = 10;
} else if (wis == 19) {
mrBonus = 15;
} else if (wis == 20) {
mrBonus = 21;
} else if (wis == 21) {
mrBonus = 28;
} else if (wis == 22) {
mrBonus = 37;
} else if (wis == 23) {
mrBonus = 47;
} else if (wis == 24) {
mrBonus = 50;
} else {
mrBonus = 50;
}
return mrBonus;
}
public static int calcDiffMr(int wis, int diff) {
return calcStatMr(wis + diff) - calcStatMr(wis);
}
/**
* 각 클래스의 LVUP시의 HP상승치를 돌려준다
*
* @param charType
* @param baseMaxHp
* @param baseCon
* @return HP상승치
*/
public static short calcStatHp(int charType, int baseMaxHp, byte baseCon) {
short randomhp = 0;
// 1. CON 보너스 로직 (확정 보너스 + 15 이하일 때 50% 확률)
if (baseCon > 15) {
// CON 16 이상: 확정 보너스
randomhp = (short) (baseCon - 15);
} else {
// CON 15 이하: 50% 확률로 0 또는 1 추가
if (rnd.nextBoolean()) {
randomhp = 1;
} else {
randomhp = 0;
}
}
// 2. 가중치 기반 추가 보너스 (1~10)
// 숫자가 낮을수록 나올 확률이 높고, 숫자가 클수록 희귀하게 설정
int[] weights = {55, 50, 45, 40, 32, 20, 15, 10, 5, 3};
int totalWeight = 0;
for (int w : weights) totalWeight += w;
int roll = rnd.nextInt(totalWeight);
int sum = 0;
int bonus = 1;
for (int i = 0; i < weights.length; i++) {
sum += weights[i];
if (roll < sum) {
bonus = (i + 1);
break;
}
}
randomhp += (short) bonus;
// 3. 기존 클래스별 랜덤 성장 로직
if (charType == 0) { // 프린스
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.PRINCE_MAX_HP) {
randomhp = (short) (Config.PRINCE_MAX_HP - baseMaxHp);
}
} else if (charType == 1) { // 나이트
randomhp += (short) (6 + rnd.nextInt(5));
if (baseMaxHp + randomhp > Config.KNIGHT_MAX_HP) {
randomhp = (short) (Config.KNIGHT_MAX_HP - baseMaxHp);
}
} else if (charType == 2) { // 에르프
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.ELF_MAX_HP) {
randomhp = (short) (Config.ELF_MAX_HP - baseMaxHp);
}
} else if (charType == 3) { // 위저드
randomhp += (short) (3 + rnd.nextInt(3));
if (baseMaxHp + randomhp > Config.WIZARD_MAX_HP) {
randomhp = (short) (Config.WIZARD_MAX_HP - baseMaxHp);
}
} else if (charType == 4) { // 다크 에르프
randomhp += (short) (5 + rnd.nextInt(4));
if (baseMaxHp + randomhp > Config.DARKELF_MAX_HP) {
randomhp = (short) (Config.DARKELF_MAX_HP - baseMaxHp);
}
}
if (randomhp < 0) {
randomhp = 0;
}
return randomhp;
}
/**
* 각 클래스의 LVUP시의 MP상승치를 돌려준다
*
* @param charType
* @param baseMaxMp
* @param baseWis
* @return MP상승치
*/
public static short calcStatMp(int charType, int baseMaxMp, byte baseWis) {
int randommp = 0;
int seed = 0;
if (baseWis <= 9) {
seed = -2;
} else if (baseWis == 10 || baseWis == 11) {
seed = -1;
} else if (baseWis >= 12 && baseWis <= 14) {
seed = 0;
} else if (baseWis >= 15 && baseWis <= 17) {
seed = 2;
} else if (baseWis == 18 || baseWis == 19) {
seed = 3;
} else if (baseWis == 20) {
seed = 4;
} else if (baseWis >= 21 && baseWis <= 23) {
seed = 5;
} else if (baseWis == 24) {
seed = 6;
} else if (baseWis == 25) {
seed = 7;
}
randommp = 2 + rnd.nextInt(3 + seed % 2 + (seed / 6) * 2) + seed / 2
- seed / 6;
if (charType == 0) { // 프린스
if (baseMaxMp + randommp > Config.PRINCE_MAX_MP) {
randommp = Config.PRINCE_MAX_MP - baseMaxMp;
}
} else if (charType == 1) { // 나이트
if (baseWis == 9) {
randommp -= 1;
} else {
randommp = (int) (1.0 * randommp / 2 + 0.5);
}
if (baseMaxMp + randommp > Config.KNIGHT_MAX_MP) {
randommp = Config.KNIGHT_MAX_MP - baseMaxMp;
}
} else if (charType == 2) { // 에르프
randommp = (int) (randommp * 1.5);
if (baseMaxMp + randommp > Config.ELF_MAX_MP) {
randommp = Config.ELF_MAX_MP - baseMaxMp;
}
} else if (charType == 3) { // 위저드
randommp *= 2;
if (baseMaxMp + randommp > Config.WIZARD_MAX_MP) {
randommp = Config.WIZARD_MAX_MP - baseMaxMp;
}
} else if (charType == 4) { // 다크 에르프
randommp = (int) (randommp * 1.5);
if (baseMaxMp + randommp > Config.DARKELF_MAX_MP) {
randommp = Config.DARKELF_MAX_MP - baseMaxMp;
}
}
if (randommp < 0) {
randommp = 0;
}
return (short) randommp;
}
}
















