28
|
1 # (at your option) any later version.
|
|
2 #
|
|
3 # This program is distributed in the hope that it will be useful,
|
|
4 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
5 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
6 # GNU General Public License for more details.
|
|
7 #
|
|
8 # You should have received a copy of the GNU General Public License
|
|
9 # along with this program; if not, write to the Free Software
|
|
10 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
11 #
|
|
12 #-------------------------------------------------------------------------
|
|
13 #
|
|
14 # Usage:
|
|
15 #
|
|
16 # Die Roller: /dieroller rq
|
|
17 #
|
|
18 # Skill Roll: [1d100.skill(50,0,0)] # ( skill%, modifer, MA% )
|
|
19 #
|
|
20 # Parry Roll: [1d100.parry(50,0,0,12)] # ( skill%, modifer, MA%, Weapon/Shield AP )
|
|
21 #
|
|
22 # Dodge Roll: [1d100.parry(50,0,0)] # ( skill%, modifer, MA% )
|
|
23 #
|
|
24 # Attack Roll: [1d100.attack(50,0,0,2,9,3,0)]
|
|
25 # ( skill%, modifer, MA%, min weap dam, max weap dam, dam bonus, truesword )
|
|
26 #
|
|
27 # Sorcery Roll: [1d100.sorcery(90, 0, 3, 6, 1, 1, 1)]
|
|
28 # (sk, mod, pow, cer, int, acc, mlt)
|
|
29 #
|
|
30 #
|
|
31 #
|
|
32 # Skill Training Unlimited Roll: [1d100.trainskill(30,75)] # (starting skill%, desired skill%)
|
|
33 # Skill Training Cost Limited: [1d100.trainskillcost(1000, 50) # (payment, starting skill%)
|
|
34 # Skill Training Time Limited: [1d100.trainskilltime(150, 50) # (time, strting skill%)
|
|
35 #
|
|
36 #-------------------------------------------------------------------------
|
|
37 # --
|
|
38 #
|
|
39 # File: rq.py
|
|
40 # Version:
|
|
41 # $Id: rq.py,v .1 pelwer
|
|
42 #
|
|
43 # Description: Runequest die roller originally based on Heroman's Hero Dieroller
|
|
44 #
|
|
45 #
|
|
46 # v.1 - pelwer - 2/5/2005
|
|
47 # o Original release
|
|
48 # v.2 - pelwer - 10/30/2006
|
|
49 # o Ported to openrpg+ by removing dependance on whrandom
|
|
50 # o Fixed Riposte spelling
|
|
51 # o Deleted sorcalc - never used
|
|
52 # o Added Sorcery Fumble table to sorcery spell roller
|
|
53 #
|
|
54
|
|
55 __version__ = "$Id: runequest.py,v Traipse 'Ornery-Orc' prof.ebral Exp $"
|
|
56
|
|
57 from time import time, clock
|
|
58 import random
|
|
59 from math import floor
|
|
60
|
|
61 from std import std
|
|
62 from orpg.dieroller.base import *
|
|
63
|
|
64 # rq stands for "Runequest"
|
|
65
|
|
66 class runequest(std):
|
|
67 name = "runequest"
|
|
68 def __init__(self,source=[]):
|
|
69 std.__init__(self,source)
|
|
70
|
|
71 def skill(self,sk,mod,ma):
|
|
72 return rqskill(self,sk,mod,ma)
|
|
73
|
|
74 def parry(self,sk,mod,ma,AP):
|
|
75 return rqparry(self,sk,mod,ma,AP)
|
|
76
|
|
77 def dodge(self,sk,mod,ma):
|
|
78 return rqdodge(self,sk,mod,ma)
|
|
79
|
|
80 def attack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd):
|
|
81 return rqattack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd)
|
|
82
|
|
83 def sorcery(self,sk,mod,pow,cer,int,acc,mlt):
|
|
84 return rqsorcery(self,sk,mod,pow,cer,int,acc,mlt)
|
|
85
|
|
86 def trainskill(self,initial,final):
|
|
87 return rqtrainskill(self,initial,final)
|
|
88
|
|
89 def trainskillcost(self,cost,sk):
|
|
90 return rqtrainskillcost(self,cost,sk)
|
|
91
|
|
92 def trainskilltime(self,time,sk):
|
|
93 return rqtrainskilltime(self,time,sk)
|
|
94
|
|
95 die_rollers.register(runequest)
|
|
96
|
|
97 # RQ Skill Training Cost/Time unlimited
|
|
98 #
|
|
99 # [1d100.trainskill(10,20)]
|
|
100 # initial skill%, final skill%
|
|
101 #
|
|
102 # sk = skill %
|
|
103 #
|
|
104 #
|
|
105 class rqtrainskill(std):
|
|
106 def __init__(self,source=[],initial=11,final=0):
|
|
107 std.__init__(self,source)
|
|
108 self.s = initial
|
|
109 self.f = final
|
|
110
|
|
111 def __str__(self):
|
|
112 myStr = "Unrestricted Training"
|
|
113 if self.s == 0:
|
|
114 myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
|
|
115 else:
|
|
116 cost = 0
|
|
117 time = 0
|
|
118 myStr = "Training: "
|
|
119 while self.s < self.f and self.s < 75:
|
|
120 cost += self.s * 5
|
|
121 time += self.s * 1
|
|
122 self.s += random.uniform(1,4) + 1
|
|
123 myStr = "Training completed:\n"
|
|
124 myStr += "\tCost(" + str(int(cost)) + ")\n"
|
|
125 myStr += "\tTime(" + str(int(time)) + ")\n"
|
|
126 myStr += "\tSkill(" + str(int(self.s)) + ")"
|
|
127 return myStr
|
|
128
|
|
129
|
|
130 # RQ Skill Training Cost Limited
|
|
131 #
|
|
132 # [1d100.trainskillcost(50,0)]
|
|
133 # cost, skill%
|
|
134 #
|
|
135 # cost = cash for training
|
|
136 # sk = skill %
|
|
137 #
|
|
138 #
|
|
139 class rqtrainskillcost(std):
|
|
140 def __init__(self,source=[],cost=11,sk=0):
|
|
141 std.__init__(self,source)
|
|
142 self.cost = cost
|
|
143 self.sk = sk
|
|
144
|
|
145 def __str__(self):
|
|
146 myStr = ""
|
|
147 if self.sk == 0 and self.cost >= 50:
|
|
148 myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
|
|
149 else:
|
|
150 cost = 0
|
|
151 time = 0
|
|
152 icost = self.sk * 5
|
|
153 myStr = "Training: "
|
|
154 while (cost + icost) < self.cost:
|
|
155 if self.sk >= 75:
|
|
156 break
|
|
157 cost += icost
|
|
158 time += self.sk * 1
|
|
159 self.sk += random.uniform(1,4) + 1
|
|
160 icost = self.sk * 5
|
|
161 myStr = "Training completed: "
|
|
162 myStr += "Cost(" + str(int(cost)) + ") "
|
|
163 myStr += "Time(" + str(int(time)) + ") "
|
|
164 myStr += "Skill(" + str(int(self.sk)) + ")"
|
|
165 return myStr
|
|
166
|
|
167
|
|
168 # RQ Skill Training Time Limited
|
|
169 #
|
|
170 # [1d100.trainskilltime(50,0)]
|
|
171 # time, skill%
|
|
172 #
|
|
173 # time = time for training
|
|
174 # sk = skill %
|
|
175 #
|
|
176 #
|
|
177 class rqtrainskilltime(std):
|
|
178 def __init__(self,source=[],time=11,sk=0):
|
|
179 std.__init__(self,source)
|
|
180 self.time = time
|
|
181 self.sk = sk
|
|
182
|
|
183 def __str__(self):
|
|
184 myStr = ""
|
|
185 if self.sk == 0 and self.time >= 20:
|
|
186 myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
|
|
187 else:
|
|
188 cost = 0
|
|
189 time = 0
|
|
190 itime = self.sk * 1
|
|
191 myStr = "Trainingsss: "
|
|
192 while (time + itime) < self.time:
|
|
193 if self.sk >= 75:
|
|
194 break
|
|
195 cost += self.sk * 5
|
|
196 time += itime
|
|
197 self.sk += random.uniform(1,4) + 1
|
|
198 itime = self.sk * 5
|
|
199 myStr = "Training completed: "
|
|
200 myStr += "Cost(" + str(int(cost)) + ") "
|
|
201 myStr += "Time(" + str(int(time)) + ") "
|
|
202 myStr += "Skill(" + str(int(self.sk)) + ")"
|
|
203 return myStr
|
|
204
|
|
205 # RQ Skill Roll
|
|
206 #
|
|
207 # [1d100.skill(50,0,0)]
|
|
208 # skill%, modifer, ma%
|
|
209 #
|
|
210 # sk = skill %
|
|
211 # mod = modifier %
|
|
212 # ma = martial arts %
|
|
213 # skill = sk + mod
|
|
214 #
|
|
215 # success roll <= skill
|
|
216 #
|
|
217 # failure roll > skill
|
|
218 #
|
|
219 # crit
|
|
220 # push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( skill/20 ) );
|
|
221 #
|
|
222 # special
|
|
223 # push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( $skill/5 ) );
|
|
224 #
|
|
225 # fumble: if ( $skill > 100 ) { $fum = 0; } else { $fum = 100 - $skill; }
|
|
226 # $fum = 100 - POSIX::floor( $fum/20 );
|
|
227 # if ( $fum == 100 ) { $fum = '00'; };
|
|
228 #
|
|
229 class rqskill(std):
|
|
230 def __init__(self,source=[],sk=11,mod=0,ma=0):
|
|
231 std.__init__(self,source)
|
|
232 self.sk = sk
|
|
233 self.mod = mod
|
|
234 self.ma = ma
|
|
235
|
|
236 def is_success(self):
|
|
237 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
|
|
238
|
|
239 def is_ma(self):
|
|
240 return (self.sum() <= self.ma)
|
|
241
|
|
242 def is_special(self):
|
|
243 return (self.sum() <= int(floor((self.sk + self.mod)/5)))
|
|
244
|
|
245 def is_critical(self):
|
|
246 return (self.sum() <= int(floor((self.sk + self.mod) / 20)))
|
|
247
|
|
248 def is_fumble(self):
|
|
249 if ( self.sk >= 100 ):
|
|
250 fum = 0
|
|
251 else:
|
|
252 fum = (100 - self.sk )
|
|
253 final_fum = ( 100 - int( floor( fum/20 ) ) )
|
|
254 return ( self.sum() >= final_fum )
|
|
255
|
|
256 def __str__(self):
|
|
257 strAdd="+"
|
|
258 swapmod= self.mod
|
|
259 if self.mod < 0:
|
|
260 strAdd= "-"
|
|
261 swapmod= -self.mod
|
|
262 modSum = self.sum()
|
|
263 # build output string
|
|
264 myStr = " (" + str(modSum) + ")"
|
|
265 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
|
|
266 if self.is_fumble():
|
|
267 myStr += " <b><font color=red>Fumble!</font></b>"
|
|
268 elif self.is_critical():
|
|
269 myStr += " <b><font color=green>Critical!</font></b>"
|
|
270 elif self.is_special():
|
|
271 myStr += " <i><font color=green>Special!</font></i>"
|
|
272 elif self.is_success() and self.is_ma():
|
|
273 myStr += " <i><font color=green>Special!</font></i>"
|
|
274 elif self.is_success():
|
|
275 myStr += " <font color=blue>Success!</font>"
|
|
276 else:
|
|
277 myStr += " <font color=red>Failure!</font>"
|
|
278 Diff = self.sk - modSum
|
|
279 myStr += " </font>"
|
|
280 return myStr
|
|
281
|
|
282 #
|
|
283 # RQ Parry Roll
|
|
284 #
|
|
285 # same as skill but with fumble dice and armor points
|
|
286 #
|
|
287 # [1d100.parry(50,0,0,12)]
|
|
288 # skill%, modifer, ma%, Weapon AP
|
|
289 #
|
|
290
|
|
291 class rqparry(std):
|
|
292 def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
|
|
293 std.__init__(self,source)
|
|
294 self.sk = sk
|
|
295 self.mod = mod
|
|
296 self.ma = ma
|
|
297 self.AP = AP
|
|
298
|
|
299 def is_success(self):
|
|
300 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
|
|
301
|
|
302 def is_special(self):
|
|
303 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
|
|
304
|
|
305 def is_ma(self):
|
|
306 return (self.sum() <= self.ma)
|
|
307
|
|
308 def is_riposte(self):
|
|
309 return (self.sum() <= (self.ma / 5))
|
|
310
|
|
311 def is_critical(self):
|
|
312 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
|
|
313
|
|
314 def is_fumble(self):
|
|
315 if ( self.sk >= 100 ):
|
|
316 fum = 0
|
|
317 else:
|
|
318 fum = (100 - self.sk )
|
|
319 final_fum = ( 100 - int( floor( fum/20 ) ) )
|
|
320 return ( self.sum() >= final_fum )
|
|
321
|
|
322 def __str__(self):
|
|
323 # get fumble roll result in case needed
|
|
324 fum_roll = random.randint(1,100)
|
|
325
|
|
326 # get special AP
|
|
327 spec_AP = int( floor ( self.AP * 1.5 ) )
|
|
328
|
|
329 # figure out +/- for modifer
|
|
330 strAdd="+"
|
|
331 swapmod= self.mod
|
|
332 if self.mod < 0:
|
|
333 strAdd= "-"
|
|
334 swapmod= -self.mod
|
|
335 modSum = self.sum()
|
|
336
|
|
337 # build output string
|
|
338 myStr = " (" + str(modSum) + ")"
|
|
339 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
|
|
340 if self.is_fumble():
|
|
341 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
|
|
342 elif self.is_critical() and self.is_riposte():
|
|
343 myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
|
|
344 myStr += " Riposte next SR"
|
|
345 elif self.is_critical():
|
|
346 myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
|
|
347 elif self.is_special and self.is_riposte():
|
|
348 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
|
|
349 myStr += " Riposte next SR"
|
|
350 elif self.is_special():
|
|
351 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
|
|
352 elif self.is_success() and self.is_ma():
|
|
353 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
|
|
354 elif self.is_success():
|
|
355 myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
|
|
356 else:
|
|
357 myStr += " <font color=red>Failure!</font>"
|
|
358 Diff = self.sk - modSum
|
|
359 myStr += " </font>"
|
|
360 return myStr
|
|
361
|
|
362 # RQ Dodge Roll
|
|
363 #
|
|
364 # same as skill but with fumble dice and armor points
|
|
365 #
|
|
366 # [1d100.parry(50,0,0)]
|
|
367 # skill%, modifer, ma%
|
|
368 #
|
|
369
|
|
370 class rqdodge(std):
|
|
371 def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
|
|
372 std.__init__(self,source)
|
|
373 self.sk = sk
|
|
374 self.mod = mod
|
|
375 self.ma = ma
|
|
376 self.AP = AP
|
|
377
|
|
378 def is_success(self):
|
|
379 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
|
|
380
|
|
381 def is_special(self):
|
|
382 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
|
|
383
|
|
384 def is_ma(self):
|
|
385 return (self.sum() <= self.ma)
|
|
386
|
|
387 def is_riposte(self):
|
|
388 return (self.sum() <= (self.ma / 5))
|
|
389
|
|
390 def is_critical(self):
|
|
391 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
|
|
392
|
|
393 def is_fumble(self):
|
|
394 if ( self.sk >= 100 ):
|
|
395 fum = 0
|
|
396 else:
|
|
397 fum = (100 - self.sk )
|
|
398 final_fum = ( 100 - int( floor( fum/20 ) ) )
|
|
399 return ( self.sum() >= final_fum )
|
|
400
|
|
401 def __str__(self):
|
|
402 # get fumble roll result in case needed
|
|
403 fum_roll = random.randint(1,100)
|
|
404
|
|
405 # get special AP
|
|
406 spec_AP = int( floor ( self.AP * 1.5 ) )
|
|
407
|
|
408 # figure out +/- for modifer
|
|
409 strAdd="+"
|
|
410 swapmod= self.mod
|
|
411 if self.mod < 0:
|
|
412 strAdd= "-"
|
|
413 swapmod= -self.mod
|
|
414 modSum = self.sum()
|
|
415
|
|
416 # build output string
|
|
417 myStr = " (" + str(modSum) + ")"
|
|
418 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
|
|
419 if self.is_fumble():
|
|
420 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
|
|
421 elif self.is_critical() and self.is_riposte():
|
|
422 myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
|
|
423 myStr += " Riposte on next SR"
|
|
424 elif self.is_critical():
|
|
425 myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
|
|
426 elif self.is_special and self.is_riposte():
|
|
427 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
|
|
428 myStr += " Riposte on next SR"
|
|
429 elif self.is_special():
|
|
430 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
|
|
431 elif self.is_success() and self.is_ma():
|
|
432 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
|
|
433 elif self.is_success():
|
|
434 myStr += " <font color=blue>Success!</font> Damage dodged</b>"
|
|
435 else:
|
|
436 myStr += " <font color=red>Failure!</font>"
|
|
437 Diff = self.sk - modSum
|
|
438 myStr += " </font>"
|
|
439 return myStr
|
|
440
|
|
441
|
|
442 #
|
|
443 # RQ Attack Roll
|
|
444 #
|
|
445 # same as skill but with fumble dice and armor points
|
|
446 #
|
|
447 # [1d100.attack(50,0,0,2,9,3,1)]
|
|
448 # skill%, modifer, ma%, min weap dam, max weap dam, dam bonus, truesword_enabled
|
|
449 #
|
|
450 class rqattack(std):
|
|
451 def __init__(self,source=[],sk=11,mod=0,ma=0,mindam=0,maxdam=0,bondam=0,trueswd=0):
|
|
452 std.__init__(self,source)
|
|
453 self.sk = sk
|
|
454 self.mod = mod
|
|
455 self.ma = ma
|
|
456 self.mindam = mindam
|
|
457 self.maxdam = maxdam
|
|
458 self.bondam = bondam
|
|
459 self.trueswd = trueswd
|
|
460
|
|
461 def is_success(self):
|
|
462 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
|
|
463
|
|
464 def is_ma(self):
|
|
465 return (self.sum() <= self.ma)
|
|
466
|
|
467 def is_special(self):
|
|
468 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
|
|
469
|
|
470 def is_critical(self):
|
|
471 return ((self.sum() <= int(floor((self.sk + self.mod) / 20))))
|
|
472
|
|
473 def is_supercritical(self):
|
|
474 return (self.sum() == 1)
|
|
475
|
|
476 def is_fumble(self):
|
|
477 if ( self.sk >= 100 ):
|
|
478 fum = 0
|
|
479 else:
|
|
480 fum = (100 - self.sk )
|
|
481 final_fum = ( 100 - int( floor( fum/20 ) ) )
|
|
482 return ( self.sum() >= final_fum )
|
|
483
|
|
484 def __str__(self):
|
|
485
|
|
486 # get fumble roll result in case needed
|
|
487 fum_roll = random.randint(1,100)
|
|
488
|
|
489 # get hit location roll result in case needed
|
|
490 location = random.randint(1,20)
|
|
491 myStr = " to the ["+ str(location) + "] "
|
|
492 if location < 5:
|
|
493 myStr += "<B>Right Leg</B>"
|
|
494 elif location < 9:
|
|
495 myStr += "<B>Left Leg</B>"
|
|
496 elif location < 12:
|
|
497 myStr += "<B>Abdomen</B>"
|
|
498 elif location < 13:
|
|
499 myStr += "<B>Chest</B>"
|
|
500 elif location < 16:
|
|
501 myStr += "<B>Right Arm</B>"
|
|
502 elif location < 19:
|
|
503 myStr += "<B>Left Arm</B>"
|
|
504 else:
|
|
505 myStr += "<B>Head</B>"
|
|
506 hit_loc = myStr
|
|
507
|
|
508 # get normal damage in case needed
|
|
509 norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
|
|
510 norm_damage_string = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
|
|
511 norm_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.bondam)
|
|
512 norm_damage_string += "}[" + str(norm_damage) + "] "
|
|
513
|
|
514 # get special/critical damage in case needed
|
|
515 crit_damage = random.randint( self.mindam*(self.trueswd+2), self.maxdam*(self.trueswd+2) ) + self.bondam
|
|
516 crit_damage_string = "{" + str( self.mindam*(self.trueswd+2) ) + "-" + str(self.maxdam*(self.trueswd+2)) + "+" + str(self.bondam) + "}[" + str(crit_damage) + "] "
|
|
517
|
|
518 # get supercritical damage in case needed
|
|
519 super_damage = norm_damage + self.maxdam
|
|
520 super_damage_string = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
|
|
521 super_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.maxdam)
|
|
522 super_damage_string += "+" + str(self.bondam) + "}[" + str(super_damage) + "] "
|
|
523
|
|
524 # figure out +/- for modifer
|
|
525 strAdd="+"
|
|
526 swapmod= self.mod
|
|
527 if self.mod < 0:
|
|
528 strAdd= "-"
|
|
529 swapmod= -self.mod
|
|
530 modSum = self.sum()
|
|
531
|
|
532 # build output string
|
|
533 myStr = " (" + str(modSum) + ")"
|
|
534 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
|
|
535 if self.is_fumble():
|
|
536 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
|
|
537 elif (self.is_supercritical() and self.is_success()):
|
|
538 myStr += " <b><font color=green>Super Critical!</font></b> Damage: " + str(super_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
|
|
539 elif (self.is_critical() and self.is_success()):
|
|
540 myStr += " <b><font color=green>Critical!</font></b> Damage: " + str(crit_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
|
|
541 elif ( self.is_special() and self.is_success() ):
|
|
542 myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
|
|
543 elif (self.is_success() and self.is_ma()):
|
|
544 myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
|
|
545 elif self.is_success():
|
|
546 myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
|
|
547 else:
|
|
548 myStr += " <font color=red>Failure!</font>"
|
|
549 return myStr
|
|
550
|
|
551 #
|
|
552 #
|
|
553 # Sorcery Roll: [1d100.sorcery(90, 10, 5, 4, 3, 2, 1)]
|
|
554 # (sk, mod, pow, cer, int, acc, mlt)
|
|
555 #
|
|
556 # Ceremony: (+1d6% per strike rank spent on ceremony)
|
|
557 # Intensity: (-3% per point of Intensity)
|
|
558 # Duration: (-4% per point of Duration)
|
|
559 # Range: (-5% per point of Range)
|
|
560 # Multispell: (-10% per each spell over 1)
|
|
561 # Acceleration: (-5% per point of Acceleration)
|
|
562 # Hold: (-2% per point in spell Held)
|
|
563 #
|
|
564 class rqsorcery(std):
|
|
565 def __init__(self,source=[],sk=11,mod=0,pow=0,cer=0,int=0,acc=0,mlt=0):
|
|
566 std.__init__(self,source)
|
|
567 self.sk = sk # sorcery skill
|
|
568 self.mod = mod # additional modifier ( from duration, range, etc )
|
|
569 self.pow = pow # boost pow and additional pow ( from duration, range, etc )
|
|
570 self.cer = cer # ceremony d6
|
|
571 self.int = int # intensity ( -3% )
|
|
572 self.acc = acc # accelerate ( -5% )
|
|
573 self.mlt = mlt # multispell ( -10% )
|
|
574
|
|
575 def is_success(self):
|
|
576 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
|
|
577
|
|
578 def is_special(self):
|
|
579 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/5 ) ) ) )
|
|
580
|
|
581 def is_critical(self):
|
|
582 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
|
|
583
|
|
584 def is_fumble(self):
|
|
585 if ( self.sk >= 100 ):
|
|
586 fum = 0
|
|
587 else:
|
|
588 fum = (100 - self.sk )
|
|
589 final_fum = ( 100 - int( floor( fum/20 ) ) )
|
|
590 return ( self.sum() >= final_fum )
|
|
591
|
|
592 def __str__(self):
|
|
593
|
|
594 # get fumble roll result in case needed
|
|
595 fum_roll = random.randint(2,12)
|
|
596 if fum_roll == 12 :
|
|
597 fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each day to remember.</font>"
|
|
598 if fum_roll == 11 :
|
|
599 fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each hour to remember. </font>"
|
|
600 if fum_roll == 10 :
|
|
601 fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect. </font>"
|
|
602 if fum_roll == 9 :
|
|
603 fum_string = "<br /><font color=purple>Caster is Stunned. Roll INTx3 to recover at SR 10 each round. </font>"
|
|
604 if fum_roll == 8 :
|
|
605 fum_string = "<br /><font color=purple>Caster takes 2D6 Damage to THP </font>"
|
|
606 if fum_roll == 7 :
|
|
607 fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect at 2x Intensity. </font>"
|
|
608 if fum_roll == 6 :
|
|
609 fum_string = "<br /><font color=purple>Spell is cast on companions (if harmful) or on random nearby foes (if beneficial) </font>"
|
|
610 if fum_roll == 5 :
|
|
611 fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to Head </font>"
|
|
612 if fum_roll == 4 :
|
|
613 fum_string = "<br /><font color=purple>Spell is cast on caster (if harmful) or on random nearby foe (if beneficial) </font>"
|
|
614 if fum_roll == 3 :
|
|
615 fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to THP </font>"
|
|
616 if fum_roll == 2 :
|
|
617 fum_string = "<br /><font color=purple>Caster takes 1 point of Damage to Head </font>"
|
|
618
|
|
619 # roll ceremony
|
|
620 ceremony_roll = random.randint( self.cer, (self.cer*6) )
|
|
621
|
|
622 # subtract manipulations
|
|
623 extra_mod = self.mod
|
|
624 self.mod += ceremony_roll - self.int*3 - self.acc*5 - self.mlt*10
|
|
625
|
|
626 # add up power cost
|
|
627 extra_pow = self.pow
|
|
628 self.pow += self.int + self.mlt + self.acc
|
|
629 special_pow = int( floor( ( self.pow )/2 ) )
|
|
630
|
|
631 # figure out +/- for modifer
|
|
632 strAdd="+"
|
|
633 swapmod= self.mod
|
|
634 if self.mod < 0:
|
|
635 strAdd= "-"
|
|
636 swapmod= -self.mod
|
|
637 modSum = self.sum()
|
|
638
|
|
639 # build output string
|
|
640 myStr = " (" + str(modSum) + ")"
|
|
641 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
|
|
642
|
|
643 if self.is_fumble():
|
|
644 myStr += " <b><font color=red>Fumble!</font> POW Cost: [" + str(self.pow) + "],</b> " + fum_string
|
|
645 elif self.is_critical():
|
|
646 myStr += " <b><font color=green>Critical!</font></b> POW Cost: [1] "
|
|
647 elif self.is_special():
|
|
648 myStr += " <i><font color=green>Special!</font></i> POW Cost: [" + str(special_pow) + "] "
|
|
649 elif self.is_success():
|
|
650 myStr += " <font color=blue>Success!</font> POW Cost: [" + str(self.pow) + "] "
|
|
651 else:
|
|
652 myStr += " <font color=red>Failure!</font> POW Cost: [1]"
|
|
653
|
|
654 # print spell details
|
|
655 myStr += "<br /> --- Other Modifiers:[" + str( extra_mod ) + "], "
|
|
656 myStr += "Extra POW:[" + str( extra_pow ) + "], "
|
|
657 myStr += "Ceremony:[+" + str( ceremony_roll ) + "%], "
|
|
658 myStr += "Intensity(-3):[" + str( self.int ) + "], "
|
|
659 myStr += "Accelerate(-5):[" + str( self.acc ) + "], "
|
|
660 myStr += "Multispell(-10):[" + str( self.mlt ) + "] ---"
|
|
661 return myStr
|
|
662
|