1 # -*- coding: utf-8 -*-
5 2013/12/19 written by kei9
11 import mh4constnumbers
12 from randomgenerator import RandomGenerator
13 from skillminmaxtable import SkillMinMaxTableAccessor
14 from skilltable import SkillTableAccessor
15 from amulettable import AmuletTableAccessor
16 from sufficienttable import SufficientTableAccessor
19 class AlchemySimulator(object):
20 u""" 特定Seed1,2から生じる錬金結果を模擬するクラス """
21 __metaclass__ = singleton.Singleton
22 def __init__(self, db_cursor):
24 self._cursor = db_cursor
25 acc_minmax = SkillMinMaxTableAccessor(db_cursor)
26 acc_skill = SkillTableAccessor(db_cursor)
27 acc_amulet = AmuletTableAccessor(db_cursor)
28 self._acc_suff = SufficientTableAccessor(db_cursor)
29 self._skill_id2name, self._skill_name2id = acc_skill.get_dict()
30 self._amu_id2name, self._amu_name2id = acc_amulet.get_dict()
31 self._minmax_dict = acc_minmax.get_minmax_by_id()
33 def _get_skill_value(self, rand1, rand2, skill_max, skill_min):
34 u""" 与えられた2つの乱数値とスキルの最大、最小値からスキル値を計算する """
35 value = (rand1 ^ rand2) % (skill_max - skill_min + 1) + skill_min # XOR
38 def alchemy_nazo_id(self, seed1, seed2):
40 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
42 gen_c = RandomGenerator(seed1) # generator C
43 gen_d = RandomGenerator(seed2) # generator D
44 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET0) # nazo
46 def alchemy_nazo_name(self, seed1, seed2):
48 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
50 val = self.alchemy_nazo_id(seed1, seed2)
51 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
52 if skill2_id in self._skill_id2name:
53 return (self._skill_id2name[skill1_id], skill1_val,
54 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
56 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
58 def alchemy_komyou_id(self, seed1, seed2):
60 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
62 gen_c = RandomGenerator(seed1) # generator C
63 gen_d = RandomGenerator(seed2) # generator D
64 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET1) # komyou
66 def alchemy_komyou_name(self, seed1, seed2):
68 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
70 val = self.alchemy_komyou_id(seed1, seed2)
71 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
72 if skill2_id in self._skill_id2name:
73 return (self._skill_id2name[skill1_id], skill1_val,
74 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
76 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
78 def alchemy_inishie_id(self, seed1, seed2):
80 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
82 gen_c = RandomGenerator(seed1) # generator C
83 gen_d = RandomGenerator(seed2) # generator D
84 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET2) # inishie
86 def alchemy_inishie_name(self, seed1, seed2):
88 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
90 val = self.alchemy_inishie_id(seed1, seed2)
91 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
92 if skill2_id in self._skill_id2name:
93 return (self._skill_id2name[skill1_id], skill1_val,
94 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
96 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
98 def alchemy_tenun_id(self, seed1, seed2, alchemy_type):
99 u""" 天運の錬金 (古*3または歪*3限定。)
100 return list of (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
102 if alchemy_type == mh4constnumbers.KEY_TENUN555:
103 result_num_max = mh4constnumbers.TENUN555_MAX
104 result_num_min = mh4constnumbers.TENUN555_MIN
105 yuga_divisor = mh4constnumbers.TENUN555_DIVISOR
106 elif alchemy_type == mh4constnumbers.KEY_TENUN888:
107 result_num_max = mh4constnumbers.TENUN888_MAX
108 result_num_min = mh4constnumbers.TENUN888_MIN
109 yuga_divisor = mh4constnumbers.TENUN888_DIVISOR
111 raise NotImplementedError(u"Irregular Alchemy Type!")
113 gen_a = RandomGenerator(seed1) # generator A
114 gen_b = RandomGenerator(seed2) # generator B
116 result_num = gen_a.get_next() % (result_num_max - result_num_min + 1) + result_num_min
119 for i in range(result_num):
120 s1 = gen_a.get_next()
121 s2 = gen_b.get_next()
122 amulet_type = s1 % yuga_divisor
123 if 0 <= amulet_type < 10:
125 amulet_name = mh4constnumbers.NAME_AMULET0
126 elif 10 <= amulet_type < 55:
128 amulet_name = mh4constnumbers.NAME_AMULET1
129 elif 55 <= amulet_type < 85:
131 amulet_name = mh4constnumbers.NAME_AMULET2
132 elif 85 <= amulet_type < 100:
134 amulet_name = mh4constnumbers.NAME_AMULET3
136 raise NotImplementedError(u"Divisor must be incorrect")
138 gen_c = RandomGenerator(s1) # generator C
139 gen_d = RandomGenerator(s2) # generator D
141 result_list.append(self._judge(gen_c, gen_d, amulet_name))
144 def alchemy_tenun_name(self, seed1, seed2, alchemy_type):
145 u""" 天運の錬金(古*3または歪*3限定。)
146 return list of (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
149 result = self.alchemy_tenun_id(seed1, seed2, alchemy_type)
150 for skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name in result:
151 if skill2_id in self._skill_id2name:
153 (self._skill_id2name[skill1_id], skill1_val,
154 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name))
156 result_list.append((self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name))
160 def _judge(self, gen_c, gen_d, amulet_name):
161 u""" 乱数生成器C,Dおよびお守りの種類から鑑定を行う
162 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
164 amulet_id = self._amu_name2id[amulet_name]
165 skill1_minmax, skill2_minmax = self._minmax_dict[amulet_id]
166 s1 = gen_c.get_next() # for skill1 dicision
167 s1 %= len(skill1_minmax) # skill1_pos
168 skill1_id = [x for i,x in enumerate(sorted(skill1_minmax.keys())) if i == s1][0]
169 min1, max1 = skill1_minmax[skill1_id]
171 x1 = gen_c.get_next()
172 x2 = gen_d.get_next()
173 skill1_val = (x1 ^ x2) % (max1 - min1 + 1) + min1 # XOR
175 y1 = gen_c.get_next()
176 y2 = gen_d.get_next()
177 border = mh4constnumbers.SKILL2_BORDER_DICT[amulet_name]
179 if (y1 ^ y2) % 100 >= border: # decide skill2 to exist
180 s2 = gen_d.get_next() # for skill2 dicision
181 s2 %= len(skill2_minmax) # skill2_pos
182 skill2_id = [x for i,x in enumerate(sorted(skill2_minmax.keys())) if i == s2][0]
183 min2, max2 = skill2_minmax[skill2_id]
186 z0 = gen_c.get_next()
190 z1 = gen_c.get_next()
191 z2 = gen_d.get_next()
192 if min2 < 0 and z0 % 2 == 0: # skill2 val is minus
193 skill2_val = (z1 ^ z2) % (1 - min2) + min2
194 else: # skill2 val is plus
195 skill2_val = (z1 ^ z2) % max2 + 1
197 if skill2_id == skill1_id or skill2_val == 0:
206 suff_val = (skill1_val * 10) // max1
208 suff_val = (skill1_val * 10) // max1 + (skill2_val * 10) // max2
211 if (w & mh4constnumbers.SEED_DECIDE_FLAG) != 0: # falg = 128, 50%
212 w2 = gen_c.get_next()
214 w2 = gen_d.get_next()
217 th1_slot, th2_slot, th3_slot = self._acc_suff.select_thresholds_by_id(amulet_id, suff_val)
220 slot_point = mh4constnumbers.SLOT_POINT0
221 elif th1_slot <= _slot < th2_slot:
223 slot_point = mh4constnumbers.SLOT_POINT1
224 elif th2_slot <= _slot < th3_slot:
226 slot_point = mh4constnumbers.SLOT_POINT2
227 elif th3_slot <= _slot:
229 slot_point = mh4constnumbers.SLOT_POINT3
231 type_name = self._decide_amulet_type(suff_val, slot_point, amulet_name)
233 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
236 def _decide_amulet_type(self, suff_val, slot_point, amulet_name):
237 u""" 鑑定結果の護石名を充足値、スロットポイント、お守り名から決定する """
238 type_val = suff_val + slot_point
240 border1, border2, border3 = mh4constnumbers.TYPE_BORDER_DICT[amulet_name]
241 if type_val >= border3[0]:
243 elif type_val >= border2[0]:
245 elif type_val >= border1[0]: # 0