Problema refine grad si clasa client Alchimie Problemă rezolvată

În cazul în care aveţi o nelămurire postaţi aici, de asemenea este locul unde puteţi găsi posibile rezolvări la problemele dvs.
Avatar utilizator
l3oogieee
Nou Venit

Nou Venit
Mesaje: 13
Membru din: 16 Mai 2024, 21:28
Regat: Jinno
Aprecieri: 13  
Mulţumiri: 0
  Rezolvări prob.: 1
Medalii

*Problemă/Întrebare:Nu imi da refine la clasa cand vreau sa le dau refine si nici la grad de claritate practic nu face nimic
Tipologie server:
*Resursă folosită:
*ServerFiles utilizat:
*Syserr:
Poză:
*Detalii suplimentare:Are idee careva unde gasesc sa modific si sa rezolv problema la refine pentru fereastra de alchimie clasa si grad de claritiate? chestia este ca daca dau sa pun un diamant sau jad ori unul din ele, imi deblocheaza toate casutele si pana nu pun full in ele nu ma lasa zice ca nu am materiale, si normal se face cu 2 deci mai e si problema asta iar daca dau cu full tot nu face nimic , nu actioneaza nimic.... nu stiu daca e din client sau sursa ori din refine proto :/
Mai e o chestie la clasa in loc de 2 cere 15 ... Si la grad de claritatate 4 ... Las aici atasat partea de dragon soul settings :
import item
import app

if app.ENABLE_DS_GRADE_MYTH:
default_grade_need_count = [15, 10, 5, 3]
default_grade_fee = [30000, 50000, 70000, 100000, 150000]
else:
default_grade_need_count = [15, 10, 5, 3]
default_grade_fee = [30000, 50000, 70000, 100000]

default_step_need_count = [4, 3, 2, 1]
default_step_fee = [20000, 30000, 40000, 50000]

strength_fee = {
item.MATERIAL_DS_REFINE_NORMAL : 10000,
item.MATERIAL_DS_REFINE_BLESSED : 20000,
item.MATERIAL_DS_REFINE_HOLLY : 30000,
}

# 강화가 어느 단계 까지 가능 한지
# table(GRADE, STEP) = max strength.
if app.ENABLE_DS_GRADE_MYTH:
default_strength_max_table = [
[2, 2, 3, 3, 4],
[3, 3, 3, 4, 4],
[4, 4, 4, 4, 4],
[4, 4, 4, 4, 5],
[4, 4, 4, 5, 6],
[4, 4, 4, 5, 6],
]
else:
default_strength_max_table = [
[2, 2, 3, 3, 4],
[3, 3, 3, 4, 4],
[4, 4, 4, 4, 4],
[4, 4, 4, 4, 5],
[4, 4, 4, 5, 6],
]

# 일단 기획적으로는 strength 강화의 경우, 강화석에 의해 fee가 셋팅되기 때문에,
# dragon_soul_refine_info에 넣지 않았다.
# (강화석만 넣어도 얼마 필요한지 보일 수 있도록 하기 위해)
# 다만 서버에서는 용혼석 타입 별로 강화석 fee를 셋팅할 수 있도록 해놨기 때문에,
# 만일 용혼석 별로 강화석 fee를 다르게 하고 싶다면,
# 클라 코드를 수정해야할 것이다.
default_refine_info = {
"grade_need_count" : default_grade_need_count,
"grade_fee" : default_grade_fee,
"step_need_count" : default_step_need_count,
"step_fee" : default_step_fee,
"strength_max_table" : default_strength_max_table,
}

dragon_soul_refine_info = {
11 : default_refine_info,
12 : default_refine_info,
13 : default_refine_info,
14 : default_refine_info,
15 : default_refine_info,
16 : default_refine_info,
}
Dragon soul table svf:
Group VnumMapper
{
#--# DragonSoulName Type
1 백룡석 11
2 화룡석 12
3 풍룡석 13
4 철룡석 14
5 뇌룡석 15
6 흑룡석 16
}

Group BasicApplys
{
Group 백룡석
{
#--# Apply_Type Apply_value
1 INT 10
2 RESIST_ICE 10
3 ATTBONUS_ICE 10
}

Group 화룡석
{
#--# Apply_Type Apply_value
1 STR 10
2 RESIST_FIRE 10
3 ATTBONUS_FIRE 10
}

Group 풍룡석
{
#--# Apply_Type Apply_value
1 MAX_SP 500
2 RESIST_WIND 10
3 ATTBONUS_WIND 10
}

Group 철룡석
{
#--# Apply_Type Apply_value
1 DEX 10
2 RESIST_EARTH 10
3 ATTBONUS_EARTH 10
}

Group 뇌룡석
{
#--# Apply_Type Apply_value
1 MAX_HP 1500
2 RESIST_ELEC 10
3 ATTBONUS_ELEC 10
}

Group 흑룡석
{
#--# Apply_Type Apply_value
1 CON 10
2 RESIST_DARK 10
3 ATTBONUS_DARK 10
}

}

Group AdditionalApplys
{
Group 백룡석
{
#--# Apply_Type Apply_value Prob
1 MAGIC_ATT_GRADE 15 10
2 MAGIC_DEF_GRADE 15 10
3 SKILL_DAMAGE_BONUS 15 10
4 SKILL_DEFEND_BONUS 15 10
}

Group 화룡석
{
#--# Apply_Type Apply_value Prob
1 ATT_BONUS 300 10
2 DEF_BONUS 200 10
3 NORMAL_HIT_DAMAGE_BONUS 15 10
4 NORMAL_HIT_DEFEND_BONUS 15 10
}

Group 풍룡석
{
#--# Apply_Type Apply_value Prob
1 MAX_HP 3000 10
2 HP_REGEN 10 10
3 STEAL_HP 10 10
4 KILL_HP_RECOVER 5 10
5 MAX_HP_PCT 20 10
}
Group 철룡석
{
#--# Apply_Type Apply_value Prob
1 ATT_BONUS_TO_WARRIOR 15 10
2 ATT_BONUS_TO_ASSASSIN 15 10
3 ATT_BONUS_TO_SURA 15 10
4 ATT_BONUS_TO_SHAMAN 15 10
5 RESIST_WARRIOR 15 10
6 RESIST_ASSASSIN 15 10
7 RESIST_SURA 15 10
8 RESIST_SHAMAN 15 10
}
Group 뇌룡석
{
#--# Apply_Type Apply_value Prob
1 MAX_SP 1500 10
2 SP_REGEN 10 10
3 STEAL_SP 10 10
4 KILL_SP_RECOVER 5 10
5 MAX_SP_PCT 20 10
}
Group 흑룡석
{
#--# Apply_Type Apply_value Prob
1 BLOCK 10 10
2 DODGE 10 10
3 REFLECT_MELEE 10 10
4 RESIST_CRITICAL 10 10
5 RESIST_PENETRATE 10 10
}

}

Group ApplyNumSettings
{
Group Default
{
#--# GRADE_NORMAL GRADE_BRILLIANT GRADE_RARE GRADE_ANCIENT GRADE_LEGENDARY GRADE_MYTH
basis 1 1 1 2 2 3
add_min 0 0 0 0 0 0
add_max 0 1 2 2 3 3
}
}

Group WeightTables
{
Group Default
{
Group GRADE_NORMAL
{
#--# 0 1 2 3 4 5 6
STEP_LOWEST 1 2 3 0 0 0 0
STEP_LOW 2 3 4 0 0 0 0
STEP_MID 3 4 5 6 0 0 0
STEP_HIGH 4 5 6 7 0 0 0
STEP_HIGHEST 5 6 7 8 10 0 0
}

Group GRADE_BRILLIANT
{
STEP_LOWEST 3 4 5 6 0 0 0
STEP_LOW 4 5 6 8 0 0 0
STEP_MID 5 6 8 10 0 0 0
STEP_HIGH 6 8 10 12 15 0 0
STEP_HIGHEST 8 10 12 15 20 0 0
}

Group GRADE_RARE
{
#--# 0 1 2 3 4 5 6
STEP_LOWEST 6 7 9 11 15 0 0
STEP_LOW 7 9 11 15 20 0 0
STEP_MID 9 11 15 20 25 0 0
STEP_HIGH 11 15 20 25 30 0 0
STEP_HIGHEST 15 20 25 30 40 0 0
}

Group GRADE_ANCIENT
{
#--# 0 1 2 3 4 5 6
STEP_LOWEST 10 12 15 18 20 0 0
STEP_LOW 12 15 18 20 25 0 0
STEP_MID 15 18 20 25 35 0 0
STEP_HIGH 18 20 25 35 40 0 0
STEP_HIGHEST 20 25 35 40 60 80 0
}

Group GRADE_LEGENDARY
{
#--# 0 1 2 3 4 5 6
STEP_LOWEST 30 35 40 45 50 0 0
STEP_LOW 35 40 45 50 55 0 0
STEP_MID 40 45 50 55 65 0 0
STEP_HIGH 45 50 55 65 75 90 0
STEP_HIGHEST 50 55 65 75 90 105 120
}

Group GRADE_MYTH
{
#--# 0 1 2 3 4 5 6
STEP_LOWEST 35 40 45 50 55 0 0
STEP_LOW 45 50 55 60 65 0 0
STEP_MID 50 55 60 70 80 0 0
STEP_HIGH 65 75 85 95 105 120 0
STEP_HIGHEST 75 85 95 105 120 135 160
}
}
}

Group RefineGradeTables
{
Group Default
{
#--# NEED_COUNT FEE GRADE_NORMAL GRADE_BRILLIANT GRADE_RARE GRADE_ANCIENT GRADE_LEGENDARY GRADE_MYTH
GRADE_NORMAL 2 30000 50 50 0 0 0 0
GRADE_BRILLIANT 2 50000 0 50 50 0 0 0
GRADE_RARE 2 70000 0 0 50 50 0 0
GRADE_ANCIENT 2 100000 0 0 0 50 50 0
GRADE_LEGENDARY 2 150000 0 0 0 0 50 50
}
}

Group RefineStepTables
{
Group Default
{
#--# NEED_COUNT FEE STEP_LOWEST STEP_LOW STEP_MID STEP_HIGH STEP_HIGHEST
STEP_LOWEST 2 20000 50 50 0 0 0
STEP_LOW 2 30000 0 50 50 0 0
STEP_MID 2 40000 0 0 50 50 0
STEP_HIGH 2 50000 0 0 0 50 50
}
}

Group RefineStrengthTables
{
Group Default
{
#--# FEE 0 1 2 3 4 5
MATERIAL_DS_REFINE_NORMAL 10000 100 80 70 50 30 20 10
MATERIAL_DS_REFINE_BLESSED 20000 100 88 77 55 33 22 12
MATERIAL_DS_REFINE_HOLLY 30000 100 90 80 60 40 30 20
}
}

Group DragonHeartExtTables
{
Group Default
{
#--# 1 2 3 4 5
CHARGING 0 5 15 30 50
GRADE_NORMAL 50 35 12 2 1
GRADE_BRILLIANT 35 40 20 4 1
GRADE_RARE 20 35 30 12 3
GRADE_ANCIENT 15 30 35 15 5
GRADE_LEGENDARY 10 20 40 20 10
GRADE_MYTH 10 20 40 20 10
}
}

Group DragonSoulExtTables
{
Group Default
{
#--# Prob ByProduct
GRADE_NORMAL 50 30270
GRADE_BRILLIANT 40 30270
GRADE_RARE 30 30270
GRADE_ANCIENT 30 30270
GRADE_LEGENDARY 100 30270
GRADE_MYTH 100 30270
}
}
Dragonsoulwindow.py
import uiScriptLocale
import app

window = {
"name" : "InventoryWindow",

## 600 - (width + 오른쪽으로 부터 띄우기 24 px)
#"x" : SCREEN_WIDTH - 176 - 287 - 10,
#"y" : SCREEN_HEIGHT - 37 - 505,

"x" : SCREEN_WIDTH - 175 - 287,
"y" : SCREEN_HEIGHT - 37 - 40 - 525,

"style" : ("movable", "float",),

"width" : 287,
"height" : 525,

"children" :
(
{
"name" : "board",
"type" : "board",
"style" : ("attach",),

"x" : 0,
"y" : 0,

"width" : 287,
"height" : 525,

"children" :
(
## Equipment Slot
{
"name" : "Equipment_Base",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"image" : "d:/ymir work/ui/dragonsoul/dragon_soul_bg.tga",

},
{
"name" : "Inventory_Tab_01", "type" : "radio_button",
"x" : 16, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_01_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_01_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_01_3.tga",
},
{
"name" : "Inventory_Tab_02", "type" : "radio_button",
"x" : 59, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_02_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_02_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_02_3.tga",
},
{
"name" : "Inventory_Tab_03", "type" : "radio_button",
"x" : 102, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_03_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_03_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_03_3.tga",
},
{
"name" : "Inventory_Tab_04", "type" : "radio_button",
"x" : 145, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_04_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_04_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_04_3.tga",
},
{
"name" : "Inventory_Tab_05", "type" : "radio_button",
"x" : 188, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_05_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_05_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_05_3.tga",
},
{
"name" : "Inventory_Tab_06", "type" : "radio_button",
"x" : 231, "y" : 331,
"default_image" : "d:/ymir work/ui/dragonsoul/btn_soul_06_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/btn_soul_06_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/btn_soul_06_3.tga",
},

## Item Slot
{
"name" : "ItemSlot",
"type" : "grid_table",

"x" : 15,
"y" : 355,

"start_index" : 0,
"x_count" : 8,
"y_count" : 4,
"x_step" : 32,
"y_step" : 32,

#"image" : "d:/ymir work/ui/public/Slot_Base.sub"
},
{
"name" : "EquipmentSlot",
"type" : "slot",

"x" : 0,
"y" : 0,

"width" : 287,
"height" : 280,

"slot" : (
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+0, "x":128, "y":53, "width":32, "height":32},
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+1, "x":59, "y":93, "width":32, "height":32},
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+2, "x":59, "y":179, "width":32, "height":32},
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+3, "x":128, "y":219, "width":32, "height":32},
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+4, "x":194, "y":179, "width":32, "height":32},
{"index":DRAGON_SOUL_EQUIPMENT_SLOT_START+5, "x":194, "y":93, "width":32, "height":32},
),
},
{
"name" : "deck1",
"type" : "toggle_button",

"x" : 21,
"y" : 230,

"default_image" : "d:/ymir work/ui/dragonsoul/deck1_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/deck1_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/deck1_3.tga",
},
{
"name" : "deck2",
"type" : "toggle_button",

"x" : 234,
"y" : 230,

"default_image" : "d:/ymir work/ui/dragonsoul/deck2_1.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/deck2_2.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/deck2_3.tga",
},
## Title
{
"name" : "TitleBar",
"type" : "titlebar",
"style" : ("attach",),

"x" : 8,
"y" : 7,

"width" : 271,
"color" : "yellow",

"children" :
(
{ "name":"TitleName", "type":"text", "x":130, "y":3, "text":uiScriptLocale.DRAGONSOUL_TITLE, "text_horizontal_align":"center" },
),
},
## Tab Area
{
"name" : "TabControl",
"type" : "window",

"x" : 10,
"y" : 279,

"width" : 267,
"height" : 30,

"children" :
(
## Tab
{
"name" : "Tab_01",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap01.tga",
},
{
"name" : "Tab_02",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap02.tga",
},
{
"name" : "Tab_03",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap03.tga",
},
{
"name" : "Tab_04",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap04.tga",
},
{
"name" : "Tab_05",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap05.tga",
},
{
"name" : "Tab_06",
"type" : "expanded_image",

"x" : 0,
"y" : 0,

"width" : 267,
"height" : 30,

"image" : "d:/ymir work/ui/dragonsoul/tap06.tga",
},
## RadioButton
{
"name" : "Tab_Button_01",
"type" : "radio_button",

"x" : 2,
"y" : 2,

"width" : 36,
"height" : 27,
},
{
"name" : "Tab_Button_02",
"type" : "radio_button",

"x" : 42,
"y" : 2,

"width" : 36,
"height" : 27,
},
{
"name" : "Tab_Button_03",
"type" : "radio_button",

"x" : 82,
"y" : 2,

"width" : 36,
"height" : 27,
},
{
"name" : "Tab_Button_04",
"type" : "radio_button",

"x" : 122,
"y" : 2,

"width" : 36,
"height" : 27,
},
{
"name" : "Tab_Button_05",
"type" : "radio_button",

"x" : 162,
"y" : 2,

"width" : 36,
"height" : 27,
},
{
"name" : "Tab_Button_06",
"type" : "radio_button",

"x" : 202,
"y" : 2,

"width" : 36,
"height" : 27,
},
),
},
{
"name" : "tab_text_area",
"type" : "text",

"x" : 18,
"y" : 315,

"text" : uiScriptLocale.DRAGONSOUL_TAP_TITLE_1,
"color" : 0xFFC0C0C0,
},
{
"name" : "activate",
"type" : "toggle_button",

"x" : 217,
"y" : 492,

"text" : uiScriptLocale.DRAGONSOUL_ACTIVATE,

"default_image" : "d:/ymir work/ui/dragonsoul/m_button01.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/m_button02.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/m_button03.tga",
},
),
},
),
}



Dragonsoulrefinewindow.py
import uiScriptLocale

window = {
"name" : "DragonSoulRefineWindow",

## 용혼석 창 바로 왼쪽
"x" : SCREEN_WIDTH - 176 - 287 - 10 - 287,
"y" : SCREEN_HEIGHT - 37 - 505,

"style" : ("movable", "float",),

"width" : 287,
"height" : 232,

"children" :
(
{
"name" : "board",
"type" : "board",
"style" : ("attach",),

"x" : 0,
"y" : 0,

"width" : 287,
"height" : 232,

"children" :
(
## Base BackGroud Image
{
"name" : "DragonSoulRefineWindowBaseImage",
"type" : "expanded_image",
"x" : 0,
"y" : 0,

"image" : "d:/ymir work/ui/dragonsoul/dragon_soul_refine_bg.tga",
},

## Title
{
"name" : "TitleBar",
"type" : "titlebar",
"style" : ("attach",),

"x" : 5,
"y" : 7,

"width" : 275,
"color" : "yellow",

"children" :
(
{
"name":"TitleName",
"type":"text",
"x":140,
"y":5,
"text":uiScriptLocale.DRAGONSOUL_REFINE_WINDOW_TITLE,
"text_horizontal_align":"center"
},
),
},

## Refine Slot
{
"name" : "RefineSlot",
"type" : "grid_table",

"image" : "d:/ymir work/ui/dragonsoul/cap.tga",

"x" : 15,
"y" : 39,

"start_index" : 0,
"x_count" : 5,
"y_count" : 3,
"x_step" : 32,
"y_step" : 32,
},

## Result Slot
{
"name" : "ResultSlot",
"type" : "grid_table",

"x" : 207,
"y" : 39,

"start_index" : 0,
"x_count" : 2,
"y_count" : 3,
"x_step" : 32,
"y_step" : 32,
},

## Grade Button
{
"name" : "GradeButton",
"type" : "toggle_button",

"x" : 36,
"y" : 148,

"default_image" : "d:/ymir work/ui/dragonsoul/button_01.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/button_02.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/button_03.tga",

"children" :
(
{
"name" : "GradeSlotTitle",
"type" : "text",
"x" : 0,
"y" : 0,
"all_align" : "center",
"text" : uiScriptLocale.GRADE_SELECT,
"color" : 0xFFF1E6C0,
},
),
},

## Step Button
{
"name" : "StepButton",
"type" : "toggle_button",

"x" : 118,
"y" : 148,

"default_image" : "d:/ymir work/ui/dragonsoul/button_01.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/button_02.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/button_03.tga",

"children" :
(
{
"name" : "StepSlotTitle",
"type" : "text",
"x" : 0,
"y" : 0,
"all_align" : "center",
"text" : uiScriptLocale.STEP_SELECT,
"color" : 0xFFF1E6C0,
},
),
},

## Refine Button
{
"name" : "StrengthButton",
"type" : "toggle_button",

"x" : 198,
"y" : 148,

"default_image" : "d:/ymir work/ui/dragonsoul/button_01.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/button_02.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/button_03.tga",

"children" :
(
{
"name" : "RefineSlotTitle",
"type" : "text",
"x" : 0,
"y" : 0,
"all_align" : "center",
"text" : uiScriptLocale.STRENGTH_SELECT,
"color" : 0xFFF1E6C0,
},
),
},

## Money Print
{
"name":"Money_Slot",
"type" : "text",

"x":35,
"y":180,

"horizontal_align" : "right",
"text_horizontal_align" : "right",

"text" : "123456789",
},

## Do Refine Button
{
"name" : "DoRefineButton",
"type" : "button",

"x" : 188,
"y" : 200,

"default_image" : "d:/ymir work/ui/dragonsoul/l_button01.tga",
"over_image" : "d:/ymir work/ui/dragonsoul/l_button02.tga",
"down_image" : "d:/ymir work/ui/dragonsoul/l_button03.tga",

"children" :
(
{
"name" : "DoRefineButtonTitle",
"type" : "text",
"x" : 0,
"y" : 0,
"text" : uiScriptLocale.DO_REFINE,
"all_align" : "center",
},
),
},
),
},
),
}


Dragonsoul.cpp
#include "stdafx.h"
#include "constants.h"
#include "item.h"
#include "item_manager.h"
#include "unique_item.h"
#include "packet.h"
#include "desc.h"
#include "char.h"
#include "dragon_soul_table.h"
#include "log.h"
#include "DragonSoul.h"
#include "../../common/service.h"
#include <boost/lexical_cast.hpp>

typedef std::vector <std::string> TTokenVector;
template <typename T> T MINMAX(T min, T value, T max)
{
T tv;

tv = (min > value ? min : value);
return (max < tv) ? max : tv;
}
int Gamble(std::vector<float>& vec_probs)
{
float range = 0.f;
for (int i = 0; i < vec_probs.size(); i++)
{
range += vec_probs;
}
float fProb = fnumber(0.f, range);
float sum = 0.f;
for (int idx = 0; idx < vec_probs.size(); idx++)
{
sum += vec_probs[idx];
if (sum >= fProb)
return idx;
}
return -1;
}

// 가중치 테이블(prob_lst)을 받아 random_set.size()개의 index를 선택하여 random_set을 return
bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int>& random_set)
{
int size = prob_lst.size();
int n = random_set.size();
if (size < n)
return false;

std::vector <int> select_bit(size, 0);
for (int i = 0; i < n; i++)
{
float range = 0.f;
for (std::list <float>::iterator it = prob_lst.begin(); it != prob_lst.end(); it++)
{
range += *it;
}
float r = fnumber (0.f, range);
float sum = 0.f;
int idx = 0;
for (std::list <float>::iterator it = prob_lst.begin(); it != prob_lst.end(); it++)
{
while (select_bit[idx++]);

sum += *it;
if (sum >= r)
{
select_bit[idx - 1] = 1;
random_set = idx - 1;
prob_lst.erase(it);
break;
}
}
}
return true;
}

/* 용혼석 Vnum에 대한 comment
* ITEM VNUM을 10만 자리부터, FEDCBA라고 한다면
* FE : 용혼석 종류. D : 등급
* C : 단계 B : 강화
* A : 여벌의 번호들...
*/

BYTE GetType(DWORD dwVnum)
{
return (dwVnum / 10000);
}

BYTE GetGradeIdx(DWORD dwVnum)
{
return (dwVnum / 1000) % 10;
}

BYTE GetStepIdx(DWORD dwVnum)
{
return (dwVnum / 100) % 10;
}

BYTE GetStrengthIdx(DWORD dwVnum)
{
return (dwVnum / 10) % 10;
}

bool DSManager::ReadDragonSoulTableFile(const char * c_pszFileName)
{
m_pTable = new DragonSoulTable();
return m_pTable->ReadDragonSoulTableFile(c_pszFileName);
}

void DSManager::GetDragonSoulInfo(DWORD dwVnum, BYTE& bType, BYTE& bGrade, BYTE& bStep, BYTE& bStrength) const
{
bType = GetType(dwVnum);
bGrade = GetGradeIdx(dwVnum);
bStep = GetStepIdx(dwVnum);
bStrength = GetStrengthIdx(dwVnum);
}

bool DSManager::IsValidCellForThisItem(const LPITEM pItem, const TItemPos& Cell) const
{
if (NULL == pItem)
return false;

WORD wBaseCell = GetBasePosition(pItem);
if (WORD_MAX == wBaseCell)
return false;

if (Cell.window_type != DRAGON_SOUL_INVENTORY
|| (Cell.cell < wBaseCell || Cell.cell >= wBaseCell + DRAGON_SOUL_BOX_SIZE))
{
return false;
}
else
return true;

}

WORD DSManager::GetBasePosition(const LPITEM pItem) const
{
if (NULL == pItem)
return WORD_MAX;

BYTE type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(pItem->GetVnum(), type, grade_idx, step_idx, strength_idx);

BYTE col_type = pItem->GetSubType();
BYTE row_type = grade_idx;
if (row_type > DRAGON_SOUL_GRADE_MAX)
return WORD_MAX;

#ifdef ENABLE_DS_GRADE_MYTH
return col_type * DRAGON_SOUL_GRADE_MAX * DRAGON_SOUL_BOX_SIZE + row_type * DRAGON_SOUL_BOX_SIZE;
#else
return col_type * DRAGON_SOUL_STEP_MAX * DRAGON_SOUL_BOX_SIZE + row_type * DRAGON_SOUL_BOX_SIZE;
#endif
}

bool DSManager::RefreshItemAttributes(LPITEM pDS)
{
if (!pDS->IsDragonSoul())
{
sys_err ("This item(ID : %d) is not DragonSoul.", pDS->GetID());
return false;
}

BYTE ds_type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(pDS->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);

DragonSoulTable::TVecApplys vec_basic_applys;
DragonSoulTable::TVecApplys vec_addtional_applys;

if (!m_pTable->GetBasicApplys(ds_type, vec_basic_applys))
{
sys_err ("There is no BasicApply about %d type dragon soul.", ds_type);
return false;
}

if (!m_pTable->GetAdditionalApplys(ds_type, vec_addtional_applys))
{
sys_err ("There is no AdditionalApply about %d type dragon soul.", ds_type);
return false;
}

// add_min과 add_max는 더미로 읽음.
int basic_apply_num, add_min, add_max;
if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max))
{
sys_err ("In ApplyNumSettings, INVALID VALUES Group type(%d), GRADE idx(%d)", ds_type, grade_idx);
return false;
}

float fWeight = 0.f;
if (!m_pTable->GetWeight(ds_type, grade_idx, step_idx, strength_idx, fWeight))
{
return false;
}
fWeight /= 100.f;

int n = MIN(basic_apply_num, vec_basic_applys.size());
for (int i = 0; i < n; i++)
{
const SApply& basic_apply = vec_basic_applys;
BYTE bType = basic_apply.apply_type;
short sValue = (short)(ceil((float)basic_apply.apply_value * fWeight - 0.01f));

pDS->SetForceAttribute(i, bType, sValue);
}

for (int i = DRAGON_SOUL_ADDITIONAL_ATTR_START_IDX; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
{
BYTE bType = pDS->GetAttributeType(i);
short sValue = 0;
if (APPLY_NONE == bType)
continue;
for (int j = 0; j < vec_addtional_applys.size(); j++)
{
if (vec_addtional_applys[j].apply_type == bType)
{
sValue = vec_addtional_applys[j].apply_value;
break;
}
}
pDS->SetForceAttribute(i, bType, (short)(ceil((float)sValue * fWeight - 0.01f)));
}
return true;
}

bool DSManager::PutAttributes(LPITEM pDS)
{
if (!pDS->IsDragonSoul())
{
sys_err ("This item(ID : %d) is not DragonSoul.", pDS->GetID());
return false;
}

BYTE ds_type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(pDS->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);

DragonSoulTable::TVecApplys vec_basic_applys;
DragonSoulTable::TVecApplys vec_addtional_applys;

if (!m_pTable->GetBasicApplys(ds_type, vec_basic_applys))
{
sys_err ("There is no BasicApply about %d type dragon soul.", ds_type);
return false;
}
if (!m_pTable->GetAdditionalApplys(ds_type, vec_addtional_applys))
{
sys_err ("There is no AdditionalApply about %d type dragon soul.", ds_type);
return false;
}


int basic_apply_num, add_min, add_max;
if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max))
{
sys_err ("In ApplyNumSettings, INVALID VALUES Group type(%d), GRADE idx(%d)", ds_type, grade_idx);
return false;
}

float fWeight = 0.f;
if (!m_pTable->GetWeight(ds_type, grade_idx, step_idx, strength_idx, fWeight))
{
return false;
}
fWeight /= 100.f;

int n = MIN(basic_apply_num, vec_basic_applys.size());
for (int i = 0; i < n; i++)
{
const SApply& basic_apply = vec_basic_applys;
BYTE bType = basic_apply.apply_type;
short sValue = (short)(ceil((float)basic_apply.apply_value * fWeight - 0.01f));

pDS->SetForceAttribute(i, bType, sValue);
}

BYTE additional_attr_num = MIN(number (add_min, add_max), 3);

std::vector <int> random_set;
if (additional_attr_num > 0)
{
random_set.resize(additional_attr_num);
std::list <float> list_probs;
for (int i = 0; i < vec_addtional_applys.size(); i++)
{
list_probs.push_back(vec_addtional_applys.prob);
}
if (!MakeDistinctRandomNumberSet(list_probs, random_set))
{
sys_err ("MakeDistinctRandomNumberSet error.");
return false;
}

for (int i = 0; i < additional_attr_num; i++)
{
int r = random_set;
const SApply& additional_attr = vec_addtional_applys[r];
BYTE bType = additional_attr.apply_type;
short sValue = (short)(ceil((float)additional_attr.apply_value * fWeight - 0.01f));

pDS->SetForceAttribute(DRAGON_SOUL_ADDITIONAL_ATTR_START_IDX + i, bType, sValue);
}
}

return true;
}

bool DSManager::DragonSoulItemInitialize(LPITEM pItem)
{
if (NULL == pItem || !pItem->IsDragonSoul())
return false;
PutAttributes(pItem);
int time = DSManager::instance().GetDuration(pItem);
if (time > 0)
pItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, time);
return true;
}

DWORD DSManager::MakeDragonSoulVnum(BYTE bType, BYTE grade, BYTE step, BYTE refine)
{
return bType * 10000 + grade * 1000 + step * 100 + refine * 10;
}

int DSManager::GetDuration(const LPITEM pItem) const
{
return pItem->GetDuration();
}

// 용혼석을 받아서 용심을 추출하는 함수
bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor)
{
if (NULL == ch || NULL == pItem)
return false;
if (pItem->IsEquipped())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("착용 중인 용혼석은 추출할 수 없습니다."));
return false;
}

DWORD dwVnum = pItem->GetVnum();
BYTE ds_type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(dwVnum, ds_type, grade_idx, step_idx, strength_idx);

int iBonus = 0;

if (NULL != pExtractor)
{
iBonus = pExtractor->GetValue(0);
}

std::vector <float> vec_chargings;
std::vector <float> vec_probs;

if (!m_pTable->GetDragonHeartExtValues(ds_type, grade_idx, vec_chargings, vec_probs))
{
return false;
}

int idx = Gamble(vec_probs);

float sum = 0.f;
if (-1 == idx)
{
sys_err ("Gamble is failed. ds_type(%d), grade_idx(%d)", ds_type, grade_idx);
return false;
}

float fCharge = vec_chargings[idx] * (100 + iBonus) / 100.f;
fCharge = MINMAX <float> (0.f, fCharge, 100.f);

if (fCharge < FLT_EPSILON)
{
pItem->SetCount(pItem->GetCount() - 1);
if (NULL != pExtractor)
{
pExtractor->SetCount(pExtractor->GetCount() - 1);
}
LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_FAIL", "");

ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용심 추출에 실패하였습니다."));
return false;
}
else
{
LPITEM pDH = ITEM_MANAGER::instance().CreateItem(DRAGON_HEART_VNUM);

if (NULL == pDH)
{
sys_err ("Cannot create DRAGON_HEART(%d).", DRAGON_HEART_VNUM);
// return NULL;
return false;
}

pItem->SetCount(pItem->GetCount() - 1);
if (NULL != pExtractor)
{
pExtractor->SetCount(pExtractor->GetCount() - 1);
}

int iCharge = (int)(fCharge + 0.5f);
pDH->SetSocket(ITEM_SOCKET_CHARGING_AMOUNT_IDX, iCharge);
ch->AutoGiveItem(pDH, true);

std::string s = boost::lexical_cast <std::string> (iCharge);
s += "%s";
LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_SUCCESS", s.c_str());
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용심 추출에 성공하였습니다."));
return true;
}
}

// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM pExtractor)
{
if (NULL == ch || NULL == pItem)
{
sys_err ("NULL POINTER. ch(%p) or pItem(%p)", ch, pItem);
return false;
}

// 목표 위치가 valid한지 검사 후, valid하지 않다면 임의의 빈 공간을 찾는다.
if (!IsValidCellForThisItem(pItem, DestCell))
{
int iEmptyCell = ch->GetEmptyDragonSoulInventory(pItem);
if (iEmptyCell < 0)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지품에 빈 공간이 없습니다."));
return false;
}
else
{
DestCell.window_type = DRAGON_SOUL_INVENTORY;
DestCell.cell = iEmptyCell;
}
}

if (!pItem->IsEquipped() || !pItem->RemoveFromCharacter())
return false;

bool bSuccess;
DWORD dwByProduct = 0;
int iBonus = 0;
float fProb;
float fDice;
// 용혼석 추출 성공 여부 결정.
{
DWORD dwVnum = pItem->GetVnum();

BYTE ds_type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);

// 추출 정보가 없다면 일단 무조건 성공하는 것이라 생각하자.
if (!m_pTable->GetDragonSoulExtValues(ds_type, grade_idx, fProb, dwByProduct))
{
pItem->AddToCharacter(ch, DestCell);
return true;
}


if (NULL != pExtractor)
{
iBonus = pExtractor->GetValue(ITEM_VALUE_DRAGON_SOUL_POLL_OUT_BONUS_IDX);
pExtractor->SetCount(pExtractor->GetCount() - 1);
}
fDice = fnumber(0.f, 100.f);
bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f);
}

// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
{
char buf[128];

if (bSuccess)
{
if (pExtractor)
{
sprintf(buf, "dice(%d) prob(%d + %d) EXTR(VN:%d)", (int)fDice, (int)fProb, iBonus, pExtractor->GetVnum());
}
else
{
sprintf(buf, "dice(%d) prob(%d)", fDice, fProb);
}
LogManager::instance().ItemLog(ch, pItem, "DS_PULL_OUT_SUCCESS", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 성공하였습니다."));
pItem->AddToCharacter(ch, DestCell);
return true;
}
else
{
if (pExtractor)
{
sprintf(buf, "dice(%d) prob(%d + %d) EXTR(VN:%d) ByProd(VN:%d)", (int)fDice, (int)fProb, iBonus, pExtractor->GetVnum(), dwByProduct);
}
else
{
sprintf(buf, "dice(%d) prob(%d) ByProd(VNUM:%d)", (int)fDice, (int)fProb, dwByProduct);
}
LogManager::instance().ItemLog(ch, pItem, "DS_PULL_OUT_FAILED", buf);
M2_DESTROY_ITEM(pItem);
pItem = NULL;
if (dwByProduct)
{
LPITEM pByProduct = ch->AutoGiveItem(dwByProduct, true);
if (pByProduct)
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하여 %s를 얻었습니다."), pByProduct->GetName());
else
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
}
else
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
}
}

return bSuccess;
}

bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE])
{
if (NULL == ch)
return false;

if (NULL == aItemPoses)
{
return false;
}

if (!ch->DragonSoul_RefineWindow_CanRefine())
{
sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName());
ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot upgrade dragon soul without refine window.");
return false;
}

// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{
if (aItemPoses.IsEquipPosition())
return false;
LPITEM pItem = ch->GetItem(aItemPoses);
if (NULL != pItem)
{
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
if (!pItem->IsDragonSoul())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));

return false;
}

set_items.insert(pItem);
}
}

if (set_items.size() == 0)
{
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS);
return false;
}

int count = set_items.size();
int need_count = 0;
int fee = 0;
std::vector <float> vec_probs;
float prob_sum;

BYTE ds_type, grade_idx, step_idx, strength_idx;
int result_grade;

// 가장 처음 것을 강화의 기준으로 삼는다.
std::set <LPITEM>::iterator it = set_items.begin();
{
LPITEM pItem = *it;

GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);

if (!m_pTable->GetRefineGradeValues(ds_type, grade_idx, need_count, fee, vec_probs))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));

return false;
}
}
while (++it != set_items.end())
{
LPITEM pItem = *it;

// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함.
if (pItem->IsEquipped())
{
return false;
}

if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum()))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));

return false;
}
}

// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
if (count != need_count)
{
sys_err ("Possiblity of invalid client. Name %s", ch->GetName());
BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL;
SendRefineResultPacket(ch, bSubHeader, NPOS);
return false;
}

if (ch->GetGold() < fee)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}

if (-1 == (result_grade = Gamble(vec_probs)))
{
sys_err ("Gamble failed. See RefineGardeTables' probabilities");
return false;
}

LPITEM pResultItem = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(ds_type, (BYTE)result_grade, 0, 0));

if (NULL == pResultItem)
{
sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(ds_type, (BYTE)result_grade, 0, 0));
return false;
}

ch->PointChange(POINT_GOLD, -fee);
int left_count = need_count;

for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++)
{
LPITEM pItem = *it;
int n = pItem->GetCount();
if (left_count > n)
{
pItem->RemoveFromCharacter();
M2_DESTROY_ITEM(pItem);
left_count -= n;
}
else
{
pItem->SetCount(n - left_count);
}
}

ch->AutoGiveItem(pResultItem, true);

if (result_grade > grade_idx)
{
char buf[128];
sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade);
LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_SUCCESS", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 성공했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return true;
}
else
{
char buf[128];
sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade);
LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_FAIL", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 실패했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return false;
}
}

bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE])
{
if (NULL == ch)
return false;
if (NULL == aItemPoses)
{
return false;
}

if (!ch->DragonSoul_RefineWindow_CanRefine())
{
sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName());
ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot use dragon soul refine window.");
return false;
}

// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{
LPITEM pItem = ch->GetItem(aItemPoses);
if (NULL != pItem)
{
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
if (!pItem->IsDragonSoul())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
set_items.insert(pItem);
}
}

if (set_items.size() == 0)
{
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS);
return false;
}

std::string stGroupName;
int count = set_items.size();
int need_count = 0;
int fee = 0;
std::vector <float> vec_probs;

BYTE ds_type, grade_idx, step_idx, strength_idx;
int result_step;

// 가장 처음 것을 강화의 기준으로 삼는다.
std::set <LPITEM>::iterator it = set_items.begin();
{
LPITEM pItem = *it;
GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);

if (!m_pTable->GetRefineStepValues(ds_type, step_idx, need_count, fee, vec_probs))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
}

while(++it != set_items.end())
{
LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함.
if (pItem->IsEquipped())
{
return false;
}
if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum()) || step_idx != GetStepIdx(pItem->GetVnum()))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
}

// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
if (count != need_count)
{
sys_err ("Possiblity of invalid client. Name %s", ch->GetName());
BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL;
SendRefineResultPacket(ch, bSubHeader, NPOS);
return false;
}

if (ch->GetGold() < fee)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}

float sum = 0.f;

if (-1 == (result_step = Gamble(vec_probs)))
{
sys_err ("Gamble failed. See RefineStepTables' probabilities");
return false;
}

LPITEM pResultItem = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(ds_type, grade_idx, (BYTE)result_step, 0));

if (NULL == pResultItem)
{
sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(ds_type, grade_idx, (BYTE)result_step, 0));
return false;
}

ch->PointChange(POINT_GOLD, -fee);
int left_count = need_count;
for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++)
{
LPITEM pItem = *it;
int n = pItem->GetCount();
if (left_count > n)
{
pItem->RemoveFromCharacter();
M2_DESTROY_ITEM(pItem);
left_count -= n;
}
else
{
pItem->SetCount(n - left_count);
}
}

ch->AutoGiveItem(pResultItem, true);
if (result_step > step_idx)
{
char buf[128];
sprintf(buf, "STEP : %d -> %d", step_idx, result_step);
LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_SUCCESS", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 성공했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return true;
}
else
{
char buf[128];
sprintf(buf, "STEP : %d -> %d", step_idx, result_step);
LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_FAIL", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 실패했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return false;
}
}

bool IsDragonSoulRefineMaterial(LPITEM pItem)
{
if (pItem->GetType() != ITEM_MATERIAL)
return false;
return (pItem->GetSubType() == MATERIAL_DS_REFINE_NORMAL ||
pItem->GetSubType() == MATERIAL_DS_REFINE_BLESSED ||
pItem->GetSubType() == MATERIAL_DS_REFINE_HOLLY);
}

bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE])
{
if (NULL == ch)
return false;
if (NULL == aItemPoses)
{
return false;
}

if (!ch->DragonSoul_RefineWindow_CanRefine())
{
sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName());
ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot use dragon soul refine window.");
return false;
}

// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{
LPITEM pItem = ch->GetItem(aItemPoses);
if (pItem)
{
set_items.insert(pItem);
}
}
if (set_items.size() == 0)
{
return false;
}

int fee;

LPITEM pRefineStone = NULL;
LPITEM pDragonSoul = NULL;
for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++)
{
LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함.
if (pItem->IsEquipped())
{
return false;
}

// 용혼석과 강화석만이 개량창에 있을 수 있다.
// 그리고 하나씩만 있어야한다.
if (pItem->IsDragonSoul())
{
if (pDragonSoul != NULL)
{
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
pDragonSoul = pItem;
}
else if(IsDragonSoulRefineMaterial(pItem))
{
if (pRefineStone != NULL)
{
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
pRefineStone = pItem;
}
else
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
}

BYTE bType, bGrade, bStep, bStrength;

if (!pDragonSoul || !pRefineStone)
{
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS);

return false;
}

if (NULL != pDragonSoul)
{
GetDragonSoulInfo(pDragonSoul->GetVnum(), bType, bGrade, bStep, bStrength);

float fWeight = 0.f;
// 가중치 값이 없다면 강화할 수 없는 용혼석
if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
return false;
}
// 강화했을 때 가중치가 0이라면 더 이상 강화되서는 안된다.
if (fWeight < FLT_EPSILON)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
return false;
}
}

float fProb;
if (!m_pTable->GetRefineStrengthValues(bType, pRefineStone->GetSubType(), bStrength, fee, fProb))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));

return false;
}

if (ch->GetGold() < fee)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}

ch->PointChange(POINT_GOLD, -fee);
LPITEM pResult = NULL;
BYTE bSubHeader;

if (fnumber(0.f, 100.f) <= fProb)
{
pResult = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(bType, bGrade, bStep, bStrength + 1));
if (NULL == pResult)
{
sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(bType, bGrade, bStep, bStrength + 1));
return false;
}
pDragonSoul->RemoveFromCharacter();

pDragonSoul->CopyAttributeTo(pResult);
RefreshItemAttributes(pResult);

pDragonSoul->SetCount(pDragonSoul->GetCount() - 1);
pRefineStone->SetCount(pRefineStone->GetCount() - 1);

char buf[128];
sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength + 1);
LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_SUCCESS", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 성공했습니다."));
ch->AutoGiveItem(pResult, true);
bSubHeader = DS_SUB_HEADER_REFINE_SUCCEED;
}
else
{
if (bStrength != 0)
{
pResult = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(bType, bGrade, bStep, bStrength - 1));
if (NULL == pResult)
{
sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(bType, bGrade, bStep, bStrength - 1));
return false;
}
pDragonSoul->CopyAttributeTo(pResult);
RefreshItemAttributes(pResult);
}
bSubHeader = DS_SUB_HEADER_REFINE_FAIL;

char buf[128];
sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength - 1);
// strength강화는 실패시 깨질 수도 있어, 원본 아이템을 바탕으로 로그를 남김.
LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_FAIL", buf);

ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 실패했습니다."));
pDragonSoul->SetCount(pDragonSoul->GetCount() - 1);
pRefineStone->SetCount(pRefineStone->GetCount() - 1);
if (NULL != pResult)
ch->AutoGiveItem(pResult, true);

}

SendRefineResultPacket(ch, bSubHeader, NULL == pResult? NPOS : TItemPos (pResult->GetWindow(), pResult->GetCell()));

return true;
}

void DSManager::SendRefineResultPacket(LPCHARACTER ch, BYTE bSubHeader, const TItemPos& pos)
{
TPacketGCDragonSoulRefine pack;
pack.bSubType = bSubHeader;

if (pos.IsValidItemPosition())
{
pack.Pos = pos;
}
LPDESC d = ch->GetDesc();
if (NULL == d)
{
return ;
}
else
{
d->Packet(&pack, sizeof(pack));
}
}

int DSManager::LeftTime(LPITEM pItem) const
{
if (pItem == NULL)
return false;

// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
{
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC);
}
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
else
{
return INT_MAX;
}
}

bool DSManager::IsTimeLeftDragonSoul(LPITEM pItem) const
{
if (pItem == NULL)
return false;

// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
{
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) > 0;
}
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
else
{
return true;
}
}

bool DSManager::IsActiveDragonSoul(LPITEM pItem) const
{
return pItem->GetSocket(ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX);
}

bool DSManager::ActivateDragonSoul(LPITEM pItem)
{
if (NULL == pItem)
return false;
LPCHARACTER pOwner = pItem->GetOwner();
if (NULL == pOwner)
return false;

int deck_idx = pOwner->DragonSoul_GetActiveDeck();

if (deck_idx < 0)
return false;

if (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DS_SLOT_MAX * deck_idx <= pItem->GetCell() &&
pItem->GetCell() < INVENTORY_MAX_NUM + WEAR_MAX_NUM + DS_SLOT_MAX * (deck_idx + 1))
{
if (IsTimeLeftDragonSoul(pItem) && !IsActiveDragonSoul(pItem))
{
char buf[128];
sprintf (buf, "LEFT TIME(%d)", LeftTime(pItem));
LogManager::instance().ItemLog(pOwner, pItem, "DS_ACTIVATE", buf);
pItem->ModifyPoints(true);
pItem->SetSocket(ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX, 1);

pItem->StartTimerBasedOnWearExpireEvent();
}
return true;
}
else
return false;
}

bool DSManager::DeactivateDragonSoul(LPITEM pItem, bool bSkipRefreshOwnerActiveState)
{
if (NULL == pItem)
return false;

LPCHARACTER pOwner = pItem->GetOwner();
if (NULL == pOwner)
return false;

if (!IsActiveDragonSoul(pItem))
return false;

char buf[128];
pItem->StopTimerBasedOnWearExpireEvent();
pItem->SetSocket(ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX, 0);
pItem->ModifyPoints(false);

sprintf (buf, "LEFT TIME(%d)", LeftTime(pItem));
LogManager::instance().ItemLog(pOwner, pItem, "DS_DEACTIVATE", buf);

if (false == bSkipRefreshOwnerActiveState)
RefreshDragonSoulState(pOwner);

return true;
}

void DSManager::RefreshDragonSoulState(LPCHARACTER ch)
{
if (NULL == ch)
return ;
for (int i = WEAR_MAX_NUM; i < WEAR_MAX_NUM + DS_SLOT_MAX * DRAGON_SOUL_DECK_MAX_NUM; i++)
{
LPITEM pItem = ch->GetWear(i);
if (pItem != NULL)
{
if(IsActiveDragonSoul(pItem))
{
return;
}
}
}
ch->DragonSoul_DeactivateAll();
}

DSManager::DSManager()
{
m_pTable = NULL;
}

DSManager::~DSManager()
{
if (m_pTable)
delete m_pTable;
}


Dragon_soul_table.cpp
#include "stdafx.h"
#include "constants.h"
#include "group_text_parse_tree.h"
#include "dragon_soul_table.h"
#include "item_manager.h"
#include "../../common/service.h"
#include <boost/lexical_cast.hpp>
const std::string g_astGradeName[] =
{
"grade_normal",
"grade_brilliant",
"grade_rare",
"grade_ancient",
"grade_legendary",
#ifdef ENABLE_DS_GRADE_MYTH
"grade_myth",
#endif
};

const std::string g_astStepName[] =
{
"step_lowest",
"step_low",
"step_mid",
"step_high",
"step_highest",
};

const std::string g_astMaterialName[] =
{
"material_leather",
"material_blood",
"material_root",
"material_needle",
"material_jewel",
"material_ds_refine_normal",
"material_ds_refine_blessed",
"material_ds_refine_holly",
};

bool DragonSoulTable::ReadDragonSoulTableFile(const char * c_pszFileName)
{
m_pLoader = new CGroupTextParseTreeLoader;
CGroupTextParseTreeLoader& loader = *m_pLoader;

if (false == loader.Load(c_pszFileName))
{
sys_err ("dragon_soul_table.txt load error");
return false;
}

// Group VnumMapper Reading.
if (!ReadVnumMapper())
return false;

// Group BasicApplys Reading.
if (!ReadBasicApplys())
return false;

// Group AdditionalApplys Reading.
if (!ReadAdditionalApplys())
return false;

m_pApplyNumSettingNode = loader.GetGroup("applynumsettings");
m_pWeightTableNode = loader.GetGroup("weighttables");
m_pRefineGradeTableNode = loader.GetGroup("refinegradetables");
m_pRefineStepTableNode = loader.GetGroup("refinesteptables");
m_pRefineStrengthTableNode = loader.GetGroup("refinestrengthtables");
m_pDragonHeartExtTableNode = loader.GetGroup("dragonheartexttables");
m_pDragonSoulExtTableNode = loader.GetGroup("dragonsoulexttables");

if (CheckApplyNumSettings()
&& CheckWeightTables()
&& CheckRefineGradeTables()
&& CheckRefineStepTables()
&& CheckRefineStrengthTables()
&& CheckDragonHeartExtTables()
&& CheckDragonSoulExtTables())
{
return true;
}
else
{
sys_err ("DragonSoul table Check failed.");
return false;
}
}

bool DragonSoulTable::GetDragonSoulGroupName(BYTE bType, std::string& stGroupName) const
{
DragonSoulTable::TMapTypeToName::const_iterator it = m_map_type_to_name.find (bType);
if (it != m_map_type_to_name.end())
{
stGroupName = it->second;
return true;
}
else
{
sys_err ("Invalid DragonSoul Type(%d)", bType);
return false;
}
}

bool DragonSoulTable::ReadVnumMapper()
{
std::string stName;

// Group VnumMapper Reading.
CGroupNode* pGroupNode = m_pLoader->GetGroup("vnummapper");

if (NULL == pGroupNode)
{
sys_err ("dragon_soul_table.txt need VnumMapper.");
return false;
}
{
int n = pGroupNode->GetRowCount();
if (0 == n)
{
sys_err ("Group VnumMapper is Empty.");
return false;
}

std::set <BYTE> setTypes;

for (int i = 0; i < n; i++)
{
const CGroupNode::CGroupNodeRow* pRow;
pGroupNode->GetRow(i, &pRow);

std::string stDragonSoulName;
BYTE bType;
if (!pRow->GetValue("dragonsoulname", stDragonSoulName))
{
sys_err ("In Group VnumMapper, No DragonSoulName column.");
return false;
}
if (!pRow->GetValue("type", bType))
{
sys_err ("In Group VnumMapper, %s's Vnum is invalid", stDragonSoulName.c_str());
return false;
}

if (setTypes.end() != setTypes.find(bType))
{
sys_err ("In Group VnumMapper, duplicated vnum exist.");
return false;
}
m_map_name_to_type.insert(TMapNameToType::value_type(stDragonSoulName, bType));
m_map_type_to_name.insert(TMapTypeToName::value_type(bType, stDragonSoulName));
m_vecDragonSoulTypes.push_back(bType);
m_vecDragonSoulNames.push_back(stDragonSoulName);
}
}
return true;
}

bool DragonSoulTable::ReadBasicApplys()
{
CGroupNode* pGroupNode = m_pLoader->GetGroup("basicapplys");

if (NULL == pGroupNode)
{
sys_err ("dragon_soul_table.txt need BasicApplys.");
return false;
}

for (uint i = 0; i < m_vecDragonSoulNames.size(); i++)
{
CGroupNode* pChild;
if (NULL == (pChild = pGroupNode->GetChildNode(m_vecDragonSoulNames[i])))
{
sys_err ("In Group BasicApplys, %s group is not defined.", m_vecDragonSoulNames[i].c_str());
return false;
}
TVecApplys vecApplys;
int n = pChild->GetRowCount();

// BasicApply Group은 Key가 1부터 시작함.
for (int j = 1; j <= n; j++)
{
std::stringstream ss;
ss << j;
const CGroupNode::CGroupNodeRow* pRow = NULL;

pChild->GetRow(ss.str(), &pRow);
if (NULL == pRow)
{
sys_err("In Group BasicApplys, No %d row.", j);
}
EApplyTypes at;
int av;

std::string stTypeName;
if (!pRow->GetValue("apply_type", stTypeName))
{
sys_err ("In Group BasicApplys, %s group's apply_type is empty.", m_vecDragonSoulNames[i].c_str());
return false;
}
if (!(at = (EApplyTypes)FN_get_apply_type(stTypeName.c_str())))
{
sys_err ("In Group BasicApplys, %s group's apply_type %s is invalid.", m_vecDragonSoulNames[i].c_str(), stTypeName.c_str());
return false;
}
if (!pRow->GetValue("apply_value", av))
{
sys_err ("In Group BasicApplys, %s group's apply_value %s is invalid.", m_vecDragonSoulNames[i].c_str(), av);
return false;
}
vecApplys.push_back(SApply(at, av));
}
m_map_basic_applys_group.insert (TMapApplyGroup::value_type (m_map_name_to_type[m_vecDragonSoulNames[i]], vecApplys));
}

return true;
}

bool DragonSoulTable::ReadAdditionalApplys()
{
CGroupNode* pGroupNode = m_pLoader->GetGroup("additionalapplys");
if (NULL == pGroupNode)
{
sys_err ("dragon_soul_table.txt need AdditionalApplys.");
return false;
}

for (int i = 0; i < m_vecDragonSoulNames.size(); i++)
{
CGroupNode* pChild;
if (NULL == (pChild = pGroupNode->GetChildNode(m_vecDragonSoulNames[i])))
{
sys_err ("In Group AdditionalApplys, %s group is not defined.", m_vecDragonSoulNames[i].c_str());
return false;
}
TVecApplys vecApplys;

int n = pChild->GetRowCount();

for (int j = 0; j < n; j++)
{
const CGroupNode::CGroupNodeRow* pRow;

pChild->GetRow(j, &pRow);

EApplyTypes at;
int av;
float prob;
std::string stTypeName;
if (!pRow->GetValue("apply_type", stTypeName))
{
sys_err ("In Group AdditionalApplys, %s group's apply_type is empty.", m_vecDragonSoulNames[i].c_str());
return false;
}
if (!(at = (EApplyTypes)FN_get_apply_type(stTypeName.c_str())))
{
sys_err ("In Group AdditionalApplys, %s group's apply_type %s is invalid.", m_vecDragonSoulNames[i].c_str(), stTypeName.c_str());
return false;
}
if (!pRow->GetValue("apply_value", av))
{
sys_err ("In Group AdditionalApplys, %s group's apply_value %s is invalid.", m_vecDragonSoulNames[i].c_str(), av);
return false;
}
if (!pRow->GetValue("prob", prob))
{
sys_err ("In Group AdditionalApplys, %s group's probability %s is invalid.", m_vecDragonSoulNames[i].c_str(), prob);
return false;
}
vecApplys.push_back(SApply(at, av, prob));
}
m_map_additional_applys_group.insert (TMapApplyGroup::value_type (m_map_name_to_type[m_vecDragonSoulNames[i]], vecApplys));
}

return true;
}

bool DragonSoulTable::CheckApplyNumSettings ()
{
// Group ApplyNumSettings Reading.
if (NULL == m_pApplyNumSettingNode)
{
sys_err ("dragon_soul_table.txt need ApplyNumSettings.");
return false;
}
else
{
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_GRADE_MAX; j++)
{
int basis, add_min, add_max;
if (!GetApplyNumSettings(m_vecDragonSoulTypes[i], j, basis, add_min, add_max))
{
sys_err ("In %s group of ApplyNumSettings, values in Grade(%s) row is invalid.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
}
}
}

return true;
}

bool DragonSoulTable::CheckWeightTables ()
{
// Group WeightTables Reading.
if (NULL == m_pWeightTableNode)
{
sys_err ("dragon_soul_table.txt need WeightTables.");
return false;
}
else
{
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_GRADE_MAX; j++)
{
for (int k = 0; k < DRAGON_SOUL_STEP_MAX; k++)
{
for (int l = 0; l < DRAGON_SOUL_STRENGTH_MAX; l++)
{
float fWeight;
if (!GetWeight(m_vecDragonSoulTypes[i], j, k, l, fWeight))
{
sys_err ("In %s group of WeightTables, value(Grade(%s), Step(%s), Strength(%d) is invalid.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str(), g_astStepName[k].c_str(), l);
}
}
}
}
}
}
return true;
}

bool DragonSoulTable::CheckRefineGradeTables()
{
// Group UpgradeTables Reading.
if (NULL == m_pRefineGradeTableNode)
{
sys_err ("dragon_soul_table.txt need RefineGradeTables.");
return false;
}
else
{
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_GRADE_MAX - 1; j++)
{
int need_count, fee;
std::vector <float> vec_probs;
if (!GetRefineGradeValues(m_vecDragonSoulTypes[i], j, need_count, fee, vec_probs))
{
sys_err ("In %s group of RefineGradeTables, values in Grade(%s) row is invalid.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (need_count < 1)
{
sys_err ("In %s group of RefineGradeTables, need_count of Grade(%s) is less than 1.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (fee < 0)
{
sys_err ("In %s group of RefineGradeTables, fee of Grade(%s) is less than 0.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (DRAGON_SOUL_GRADE_MAX != vec_probs.size())
{
sys_err ("In %s group of RefineGradeTables, probability list size is not %d.", DRAGON_SOUL_GRADE_MAX);
return false;
}
for (int k = 0; k < vec_probs.size(); k++)
{
if (vec_probs[k] < 0.f)
{
sys_err ("In %s group of RefineGradeTables, probability(index : %d) is less than 0.", k);
return false;
}
}
}
}
}

return true;
}

bool DragonSoulTable::CheckRefineStepTables ()
{
// Group ImproveTables Reading.
if (NULL == m_pRefineStrengthTableNode)
{
sys_err ("dragon_soul_table.txt need RefineStepTables.");
return false;
}
else
{
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_STEP_MAX - 1; j++)
{
int need_count, fee;
std::vector <float> vec_probs;
if (!GetRefineStepValues(m_vecDragonSoulTypes[i], j, need_count, fee, vec_probs))
{
sys_err ("In %s group of RefineStepTables, values in Step(%s) row is invalid.",
m_vecDragonSoulNames[i].c_str(), g_astStepName[j].c_str());
return false;
}
if (need_count < 1)
{
sys_err ("In %s group of RefineStepTables, need_count of Step(%s) is less than 1.",
m_vecDragonSoulNames[i].c_str(), g_astStepName[j].c_str());
return false;
}
if (fee < 0)
{
sys_err ("In %s group of RefineStepTables, fee of Step(%s) is less than 0.",
m_vecDragonSoulNames[i].c_str(), g_astStepName[j].c_str());
return false;
}
if (DRAGON_SOUL_STEP_MAX != vec_probs.size())
{
sys_err ("In %s group of RefineStepTables, probability list size is not %d.", m_vecDragonSoulNames[i].c_str(), DRAGON_SOUL_STEP_MAX);
return false;
}
for (int k = 0; k < vec_probs.size(); k++)
{
if (vec_probs[k] < 0.f)
{
sys_err ("In %s group of RefineStepTables, probability(index : %d) is less than 0.",
m_vecDragonSoulNames[i].c_str(), k);
return false;
}
}
}
}
}

return true;
}


bool DragonSoulTable::CheckRefineStrengthTables()
{
CGroupNode* pGroupNode = m_pRefineStrengthTableNode;
// Group RefineTables Reading.
if (NULL == pGroupNode)
{
sys_err ("dragon_soul_table.txt need RefineStrengthTables.");
return false;
}
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = MATERIAL_DS_REFINE_NORMAL; j <= MATERIAL_DS_REFINE_HOLLY; j++)
{
int fee;
float prob;
for (int k = 0; k < DRAGON_SOUL_STRENGTH_MAX -1; k++)
{
if (!GetRefineStrengthValues(m_vecDragonSoulTypes[i], j, k, fee, prob))
{
sys_err ("In %s group of RefineStrengthTables, value(Material(%s), Strength(%d)) or fee are invalid.",
m_vecDragonSoulNames[i].c_str(), g_astMaterialName[j].c_str(), k);
return false;
}
if (fee < 0)
{
sys_err ("In %s group of RefineStrengthTables, fee of Material(%s) is less than 0.",
m_vecDragonSoulNames[i].c_str(), g_astMaterialName[j].c_str());
return false;
}
if (prob < 0.f)
{
sys_err ("In %s group of RefineStrengthTables, probability(Material(%s), Strength(%d)) is less than 0.",
m_vecDragonSoulNames[i].c_str(), g_astMaterialName[j].c_str(), k);
return false;
}
}
}
}

return true;
}

bool DragonSoulTable::CheckDragonHeartExtTables()
{
// Group DragonHeartExtTables Reading.
if (NULL == m_pDragonHeartExtTableNode)
{
sys_err ("dragon_soul_table.txt need DragonHeartExtTables.");
return false;
}
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_GRADE_MAX; j++)
{
std::vector <float> vec_chargings;
std::vector <float> vec_probs;

if (!GetDragonHeartExtValues(m_vecDragonSoulTypes[i], j, vec_chargings, vec_probs))
{
sys_err ("In %s group of DragonHeartExtTables, CHARGING row or Grade(%s) row are invalid.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (vec_chargings.size() != vec_probs.size())
{
sys_err ("In %s group of DragonHeartExtTables, CHARGING row size(%d) are not equal Grade(%s) row size(%d).",
m_vecDragonSoulNames[i].c_str(), vec_chargings.size(), vec_probs.size());
return false;
}
for (int k = 0; k < vec_chargings.size(); k++)
{
if (vec_chargings[k] < 0.f)
{
sys_err ("In %s group of DragonHeartExtTables, CHARGING value(index : %d) is less than 0",
m_vecDragonSoulNames[i].c_str(), k);
return false;
}
}
for (int k = 0; k < vec_probs.size(); k++)
{
if (vec_probs[k] < 0.f)
{
sys_err ("In %s group of DragonHeartExtTables, Probability(Grade : %s, index : %d) is less than 0",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str(), k);
return false;
}
}
}
}

return true;
}

bool DragonSoulTable::CheckDragonSoulExtTables()
{
// Group DragonSoulExtTables Reading.
if (NULL == m_pDragonSoulExtTableNode)
{
sys_err ("dragon_soul_table.txt need DragonSoulExtTables.");
return false;
}
for (int i = 0; i < m_vecDragonSoulTypes.size(); i++)
{
for (int j = 0; j < DRAGON_SOUL_GRADE_MAX; j++)
{
float prob;
DWORD by_product;
if (!GetDragonSoulExtValues(m_vecDragonSoulTypes[i], j, prob, by_product))
{
sys_err ("In %s group of DragonSoulExtTables, Grade(%s) row is invalid.",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (prob < 0.f)
{
sys_err ("In %s group of DragonSoulExtTables, Probability(Grade : %s) is less than 0",
m_vecDragonSoulNames[i].c_str(), g_astGradeName[j].c_str());
return false;
}
if (0 != by_product && NULL == ITEM_MANAGER::instance().GetTable(by_product))
{
sys_err ("In %s group of DragonSoulExtTables, ByProduct(%d) of Grade %s is not exist.",
m_vecDragonSoulNames[i].c_str(), by_product, g_astGradeName[j].c_str());
return false;
}
}
}
return true;
}

bool DragonSoulTable::GetBasicApplys(BYTE ds_type, OUT TVecApplys& vec_basic_applys)
{
TMapApplyGroup::iterator it = m_map_basic_applys_group.find(ds_type);
if (m_map_basic_applys_group.end() == it)
{
return false;
}
vec_basic_applys = it->second;
return true;
}

bool DragonSoulTable::GetAdditionalApplys(BYTE ds_type, OUT TVecApplys& vec_additional_applys)
{
TMapApplyGroup::iterator it = m_map_additional_applys_group.find(ds_type);
if (m_map_additional_applys_group.end() == it)
{
return false;
}
vec_additional_applys = it->second;
return true;
}

bool DragonSoulTable::GetApplyNumSettings(BYTE ds_type, BYTE grade_idx, OUT int& basis, OUT int& add_min, OUT int& add_max)
{
if (grade_idx >= DRAGON_SOUL_GRADE_MAX)
{
sys_err ("Invalid dragon soul grade_idx(%d).", grade_idx);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

if (!m_pApplyNumSettingNode->GetGroupValue(stDragonSoulName, "basis", g_astGradeName[grade_idx], basis))
{
sys_err ("Invalid basis value. DragonSoulGroup(%s) Grade(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

if (!m_pApplyNumSettingNode->GetGroupValue(stDragonSoulName, "add_min", g_astGradeName[grade_idx], add_min))
{
sys_err ("Invalid add_min value. DragonSoulGroup(%s) Grade(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

if (!m_pApplyNumSettingNode->GetGroupValue(stDragonSoulName, "add_max", g_astGradeName[grade_idx], add_max))
{
sys_err ("Invalid add_max value. DragonSoulGroup(%s) Grade(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

return true;
}

bool DragonSoulTable::GetWeight(BYTE ds_type, BYTE grade_idx, BYTE step_index, BYTE strength_idx, OUT float& fWeight)
{
if (grade_idx >= DRAGON_SOUL_GRADE_MAX || step_index >= DRAGON_SOUL_STEP_MAX || strength_idx >= DRAGON_SOUL_STRENGTH_MAX)
{
sys_err ("Invalid dragon soul grade_idx(%d) step_index(%d) strength_idx(%d).", grade_idx, step_index, strength_idx);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

CGroupNode* pDragonSoulGroup = m_pWeightTableNode->GetChildNode(stDragonSoulName);
if (NULL != pDragonSoulGroup)
{
if (pDragonSoulGroup->GetGroupValue(g_astGradeName[grade_idx], g_astStepName[step_index], strength_idx, fWeight))
{
return true;
}
}
// default group을 살펴봄.
pDragonSoulGroup = m_pWeightTableNode->GetChildNode("default");
if (NULL != pDragonSoulGroup)
{
if (!pDragonSoulGroup->GetGroupValue(g_astGradeName[grade_idx], g_astStepName[step_index], strength_idx, fWeight))
{
sys_err ("Invalid float. DragonSoulGroup(%s) Grade(%s) Row(%s) Col(%d))", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), g_astStepName[step_index].c_str(), strength_idx);
return false;
}
else
return true;
}
sys_err ("Invalid value. DragonSoulGroup(%s) Grade(%s) Row(%s) Col(%d))", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), g_astStepName[step_index].c_str(), strength_idx);
return false;
}

bool DragonSoulTable::GetRefineGradeValues(BYTE ds_type, BYTE grade_idx, OUT int& need_count, OUT int& fee, OUT std::vector<float>& vec_probs)
{
if (grade_idx >= DRAGON_SOUL_GRADE_MAX -1)
{
sys_err ("Invalid dragon soul grade_idx(%d).", grade_idx);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

const CGroupNode::CGroupNodeRow * pRow;
if (!m_pRefineGradeTableNode->GetGroupRow(stDragonSoulName, g_astGradeName[grade_idx], &pRow))
{
sys_err ("Invalid row. DragonSoulGroup(%s) Grade(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

if (!pRow->GetValue("need_count", need_count))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Grade(%s) Col(need_count)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

if (!pRow->GetValue("fee", fee))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Grade(%s) Col(fee)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

vec_probs.resize(DRAGON_SOUL_GRADE_MAX);
for (int i = 0; i < DRAGON_SOUL_GRADE_MAX; i++)
{
if (!pRow->GetValue(g_astGradeName[i], vec_probs[i]))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Grade(%s) Col(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), g_astGradeName[i].c_str());
return false;
}
}

return true;
}

bool DragonSoulTable::GetRefineStepValues(BYTE ds_type, BYTE step_idx, OUT int& need_count, OUT int& fee, OUT std::vector<float>& vec_probs)
{
if (step_idx >= DRAGON_SOUL_STEP_MAX - 1)
{
sys_err ("Invalid dragon soul step_idx(%d).", step_idx);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

const CGroupNode::CGroupNodeRow * pRow;
if (!m_pRefineStepTableNode->GetGroupRow(stDragonSoulName, g_astStepName[step_idx], &pRow))
{
sys_err ("Invalid row. DragonSoulGroup(%s) Step(%s)", stDragonSoulName.c_str(), g_astStepName[step_idx].c_str());
return false;
}

if (!pRow->GetValue("need_count", need_count))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Step(%s) Col(need_count)", stDragonSoulName.c_str(), g_astStepName[step_idx].c_str());
return false;
}

if (!pRow->GetValue("fee", fee))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Step(%s) Col(fee)", stDragonSoulName.c_str(), g_astStepName[step_idx].c_str());
return false;
}

vec_probs.resize(DRAGON_SOUL_STEP_MAX);
for (int i = 0; i < DRAGON_SOUL_STEP_MAX; i++)
{
if (!pRow->GetValue(g_astStepName[i], vec_probs[i]))
{
sys_err ("Invalid value. DragonSoulGroup(%s) Step(%s) Col(%s)", stDragonSoulName.c_str(), g_astStepName[step_idx].c_str(), g_astStepName[i].c_str());
return false;
}
}

return true;
}

bool DragonSoulTable::GetRefineStrengthValues(BYTE ds_type, BYTE material_type, BYTE strength_idx, OUT int& fee, OUT float& prob)
{
if (material_type < MATERIAL_DS_REFINE_NORMAL || material_type > MATERIAL_DS_REFINE_HOLLY)
{
sys_err ("Invalid dragon soul material_type(%d).", material_type);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

if (!m_pRefineStrengthTableNode->GetGroupValue(stDragonSoulName, g_astMaterialName[material_type], "fee", fee))
{
sys_err ("Invalid fee. DragonSoulGroup(%s) Material(%s)",
stDragonSoulName.c_str(), g_astMaterialName[material_type].c_str());
return false;
}
std::string stStrengthIdx = boost::lexical_cast <std::string> ((int)strength_idx);

if (!m_pRefineStrengthTableNode->GetGroupValue(stDragonSoulName, g_astMaterialName[material_type], stStrengthIdx, prob))
{
sys_err ("Invalid prob. DragonSoulGroup(%s) Material(%s) Strength(%d)",
stDragonSoulName.c_str(), g_astMaterialName[material_type].c_str(), strength_idx);
return false;
}

return true;
}

bool DragonSoulTable::GetDragonHeartExtValues(BYTE ds_type, BYTE grade_idx, OUT std::vector<float>& vec_chargings, OUT std::vector<float>& vec_probs)
{
if (grade_idx >= DRAGON_SOUL_GRADE_MAX)
{
sys_err ("Invalid dragon soul grade_idx(%d).", grade_idx);
return false;
}

std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

const CGroupNode::CGroupNodeRow * pRow;
if (!m_pDragonHeartExtTableNode->GetGroupRow(stDragonSoulName, "charging", &pRow))
{
sys_err ("Invalid CHARGING row. DragonSoulGroup(%s)", stDragonSoulName.c_str());
return false;
}
int n = pRow->GetSize();
vec_chargings.resize(n);
for (int i = 0; i < n; i++)
{
if (!pRow->GetValue(i, vec_chargings[i]))
{
sys_err ("Invalid CHARGING value. DragonSoulGroup(%s), Col(%d)", stDragonSoulName.c_str(), i);
return false;
}
}

if (!m_pDragonHeartExtTableNode->GetGroupRow(stDragonSoulName, g_astGradeName[grade_idx], &pRow))
{
sys_err ("Invalid row. DragonSoulGroup(%s) Grade(%s)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

int m = pRow->GetSize();
if (n != m)
{
sys_err ("Invalid row size(%d). It must be same CHARGING row size(%d). DragonSoulGroup(%s) Grade(%s)", m, n,
stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str());
return false;
}
vec_probs.resize(m);
for (int i = 0; i < m; i++)
{
if (!pRow->GetValue(i, vec_probs[i]))
{
sys_err ("Invalid value. DragonSoulGroup(%s), Grade(%s) Col(%d)", stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), i);
return false;
}
}

return true;
}

bool DragonSoulTable::GetDragonSoulExtValues(BYTE ds_type, BYTE grade_idx, OUT float& prob, OUT DWORD& by_product)
{
if (grade_idx >= DRAGON_SOUL_GRADE_MAX)
{
sys_err ("Invalid dragon soul grade_idx(%d).", grade_idx);
return false;
}

std::string stValue;
std::string stDragonSoulName;
if (!GetDragonSoulGroupName(ds_type, stDragonSoulName))
{
sys_err ("Invalid dragon soul type(%d).", ds_type);
return false;
}

if (!m_pDragonSoulExtTableNode->GetGroupValue(stDragonSoulName, g_astGradeName[grade_idx], "prob", prob))
{
sys_err ("Invalid Prob. DragonSoulGroup(%s) Grade(%s)",
stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), g_astGradeName[grade_idx].c_str());
return false;
}

if (!m_pDragonSoulExtTableNode->GetGroupValue(stDragonSoulName, g_astGradeName[grade_idx], "byproduct", by_product))
{
sys_err ("Invalid fee. DragonSoulGroup(%s) Grade(%d)",
stDragonSoulName.c_str(), g_astGradeName[grade_idx].c_str(), grade_idx);
return false;
}

return true;
}

DragonSoulTable::DragonSoulTable()
{
m_pLoader = NULL;
}
DragonSoulTable::~DragonSoulTable ()
{
if (m_pLoader)
delete m_pLoader;
}
Ultima oară modificat 08 Iul 2024, 00:56 de către l3oogieee, modificat de 2 ori în total.
Avatar utilizator
Titan
Metin Master

Metin Master
Mesaje: 2783
Membru din: 01 Iun 2015, 15:09
Server: In curand.
Regat: Chunjo
Aprecieri: 42  
Mulţumiri: 377  
  Rezolvări prob.: 3
Discord: Copiază ID
 Contact:
Medalii

Alchimia nu are treabă cu refine_proto, dacă ai făcut modificări în dragon_soul_table.txt trebuie să modifici și în client în fișierele responsabile dragonsoul pe care le găsești în root. Dacă partea de client nu este 1 la 1 cu partea de server apar neregulile pe care le ai prezente.
Pentru acest mesaj, Titan for the post:
l3oogieee
Imagine
Afișează semnătura
Avatar utilizator
l3oogieee
Nou Venit

Nou Venit
Mesaje: 13
Membru din: 16 Mai 2024, 21:28
Regat: Jinno
Aprecieri: 13  
Mulţumiri: 0
  Rezolvări prob.: 1
Medalii

Titan scrie: ↑06 Iul 2024, 23:51 Alchimia nu are treabă cu refine_proto, dacă ai făcut modificări în dragon_soul_table.txt trebuie să modifici și în client în fișierele responsabile dragonsoul pe care le găsești în root. Dacă partea de client nu este 1 la 1 cu partea de server apar neregulile pe care le ai prezente.
Edit, am pus toate fisierele gasite in speranta ca poate imi zici la care si unde sunt liniile care raspund de actiunea de refine si care cere cantitate la clasa si la grad clarittate...

Rezolvat !!!!

In liniile din client setting al tabelului respectiv pentru dragon soul :

Cod: Selectaţi tot

if app.ENABLE_DS_GRADE_MYTH:
default_grade_need_count = [15, 10, 5, 3]
default_grade_fee = [30000, 50000, 70000, 100000, 150000]
else:
default_grade_need_count = [15, 10, 5, 3]
default_grade_fee = [30000, 50000, 70000, 100000]
need count are 15 prima data si acolo este cat sa ceara iar logic din svf este de 2 setata asa ca era conflict si nu avea cum sa dea refine, am setat la ambele grad need count 2, 10, 5, 3 / 2, 10 ,5, 3! Merciiii!!
Răspunde
Răspunsuri
2
Vizualizări
226
Răspunsuri
0
Vizualizări
1008
Răspunsuri
1
Vizualizări
100
Răspunsuri
2
Vizualizări
57

Înapoi la “Probleme şi Întrebări”

  • Informaţie
  • Cine este conectat

    Utilizatori ce ce navighează pe acest forum: Niciun utilizator înregistrat și 3 vizitatori