comparison orpg/dieroller/rollers/runequest.py @ 167:5c9a118476b2 alpha

Traipse Alpha 'OpenRPG' {091210-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Keeping up with Beta) New Features: Added Bookmarks Added 'boot' command to remote admin Added confirmation window for sent nodes Minor changes to allow for portability to an OpenSUSE linux OS Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Zoom Mouse plugin added Images added to Plugin UI Switching to Element Tree Map efficiency, from FlexiRPG Added Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) Portable Mercurial Tip of the Day added, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Parent Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added Dieroller structure from Core Added 7th Sea die roller method; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added Added new vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Includes support for Mythos roller Fixes: Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fixed Whiteboard ID to prevent random line or text deleting. Modified ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and no reactive settings when Ok is pressed Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of a Splice
author sirebral
date Thu, 10 Dec 2009 10:53:33 -0600
parents
children dcae32e219f1
comparison
equal deleted inserted replaced
166:eef2463cd441 167:5c9a118476b2
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 1.4 2006/11/15 12:11:22 digitalxero 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 # these methods return new die objects for specific options
72
73 def skill(self,sk,mod,ma):
74 return rqskill(self,sk,mod,ma)
75
76 def parry(self,sk,mod,ma,AP):
77 return rqparry(self,sk,mod,ma,AP)
78
79 def dodge(self,sk,mod,ma):
80 return rqdodge(self,sk,mod,ma)
81
82 def attack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd):
83 return rqattack(self,sk,mod,ma,mindam,maxdam,bondam,trueswd)
84
85 def sorcery(self,sk,mod,pow,cer,int,acc,mlt):
86 return rqsorcery(self,sk,mod,pow,cer,int,acc,mlt)
87
88 def trainskill(self,initial,final):
89 return rqtrainskill(self,initial,final)
90
91 def trainskillcost(self,cost,sk):
92 return rqtrainskillcost(self,cost,sk)
93
94 def trainskilltime(self,time,sk):
95 return rqtrainskilltime(self,time,sk)
96
97 die_rollers.register(runequest)
98
99 # RQ Skill Training Cost/Time unlimited
100 #
101 # [1d100.trainskill(10,20)]
102 # initial skill%, final skill%
103 #
104 # sk = skill %
105 #
106 #
107 class rqtrainskill(std):
108 def __init__(self,source=[],initial=11,final=0):
109 std.__init__(self,source)
110 self.s = initial
111 self.f = final
112
113 def __str__(self):
114 myStr = "Unrestricted Training"
115
116 if self.s == 0:
117 myStr = "Initial training completed for Cost(50) Time(20) Skill(1 + modifier)"
118 else:
119 cost = 0
120 time = 0
121 myStr = "Training: "
122
123 while self.s < self.f and self.s < 75:
124 cost += self.s * 5
125 time += self.s * 1
126 self.s += random.uniform(1,4) + 1
127
128 myStr = "Training completed:\n"
129 myStr += "\tCost(" + str(int(cost)) + ")\n"
130 myStr += "\tTime(" + str(int(time)) + ")\n"
131 myStr += "\tSkill(" + str(int(self.s)) + ")"
132
133 return myStr
134
135
136 # RQ Skill Training Cost Limited
137 #
138 # [1d100.trainskillcost(50,0)]
139 # cost, skill%
140 #
141 # cost = cash for training
142 # sk = skill %
143 #
144 #
145 class rqtrainskillcost(std):
146 def __init__(self,source=[],cost=11,sk=0):
147 std.__init__(self,source)
148 self.cost = cost
149 self.sk = sk
150
151 def __str__(self):
152 myStr = ""
153
154 if self.sk == 0 and self.cost >= 50:
155 myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
156 else:
157 cost = 0
158 time = 0
159 icost = self.sk * 5
160
161 myStr = "Training: "
162
163 while (cost + icost) < self.cost:
164 if self.sk >= 75:
165 break
166
167 cost += icost
168 time += self.sk * 1
169 self.sk += random.uniform(1,4) + 1
170 icost = self.sk * 5
171
172 myStr = "Training completed: "
173 myStr += "Cost(" + str(int(cost)) + ") "
174 myStr += "Time(" + str(int(time)) + ") "
175 myStr += "Skill(" + str(int(self.sk)) + ")"
176
177 return myStr
178
179
180 # RQ Skill Training Time Limited
181 #
182 # [1d100.trainskilltime(50,0)]
183 # time, skill%
184 #
185 # time = time for training
186 # sk = skill %
187 #
188 #
189 class rqtrainskilltime(std):
190 def __init__(self,source=[],time=11,sk=0):
191 std.__init__(self,source)
192 self.time = time
193 self.sk = sk
194
195 def __str__(self):
196 myStr = ""
197
198 if self.sk == 0 and self.time >= 20:
199 myStr = "Initial training completed for Cost(50), Time(50), Skill(1 + modifier)"
200 else:
201 cost = 0
202 time = 0
203 itime = self.sk * 1
204
205 myStr = "Trainingsss: "
206
207 while (time + itime) < self.time:
208 if self.sk >= 75:
209 break
210
211 cost += self.sk * 5
212 time += itime
213 self.sk += random.uniform(1,4) + 1
214 itime = self.sk * 5
215
216 myStr = "Training completed: "
217 myStr += "Cost(" + str(int(cost)) + ") "
218 myStr += "Time(" + str(int(time)) + ") "
219 myStr += "Skill(" + str(int(self.sk)) + ")"
220
221 return myStr
222
223 # RQ Skill Roll
224 #
225 # [1d100.skill(50,0,0)]
226 # skill%, modifer, ma%
227 #
228 # sk = skill %
229 # mod = modifier %
230 # ma = martial arts %
231 # skill = sk + mod
232 #
233 # success roll <= skill
234 #
235 # failure roll > skill
236 #
237 # crit
238 # push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( skill/20 ) );
239 #
240 # special
241 # push( @{$::Cre{Weapons}{$weap_cnt}}, POSIX::floor( $skill/5 ) );
242 #
243 # fumble: if ( $skill > 100 ) { $fum = 0; } else { $fum = 100 - $skill; }
244 # $fum = 100 - POSIX::floor( $fum/20 );
245 # if ( $fum == 100 ) { $fum = '00'; };
246 #
247 class rqskill(std):
248 def __init__(self,source=[],sk=11,mod=0,ma=0):
249 std.__init__(self,source)
250 self.sk = sk
251 self.mod = mod
252 self.ma = ma
253
254 def is_success(self):
255 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
256
257 def is_ma(self):
258 return (self.sum() <= self.ma)
259
260 def is_special(self):
261 return (self.sum() <= int(floor((self.sk + self.mod)/5)))
262
263 def is_critical(self):
264 return (self.sum() <= int(floor((self.sk + self.mod) / 20)))
265
266 def is_fumble(self):
267 if ( self.sk >= 100 ):
268 fum = 0
269 else:
270 fum = (100 - self.sk )
271 final_fum = ( 100 - int( floor( fum/20 ) ) )
272 return ( self.sum() >= final_fum )
273
274 def __str__(self):
275 strAdd="+"
276 swapmod= self.mod
277 if self.mod < 0:
278 strAdd= "-"
279 swapmod= -self.mod
280 modSum = self.sum()
281 # build output string
282 myStr = " (" + str(modSum) + ")"
283 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
284
285 if self.is_fumble():
286 myStr += " <b><font color=red>Fumble!</font></b>"
287 elif self.is_critical():
288 myStr += " <b><font color=green>Critical!</font></b>"
289 elif self.is_special():
290 myStr += " <i><font color=green>Special!</font></i>"
291 elif self.is_success() and self.is_ma():
292 myStr += " <i><font color=green>Special!</font></i>"
293 elif self.is_success():
294 myStr += " <font color=blue>Success!</font>"
295 else:
296 myStr += " <font color=red>Failure!</font>"
297
298 Diff = self.sk - modSum
299 myStr += " </font>"
300
301 return myStr
302
303 #
304 # RQ Parry Roll
305 #
306 # same as skill but with fumble dice and armor points
307 #
308 # [1d100.parry(50,0,0,12)]
309 # skill%, modifer, ma%, Weapon AP
310 #
311
312 class rqparry(std):
313 def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
314 std.__init__(self,source)
315 self.sk = sk
316 self.mod = mod
317 self.ma = ma
318 self.AP = AP
319
320 def is_success(self):
321 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
322
323 def is_special(self):
324 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
325
326 def is_ma(self):
327 return (self.sum() <= self.ma)
328
329 def is_riposte(self):
330 return (self.sum() <= (self.ma / 5))
331
332 def is_critical(self):
333 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
334
335 def is_fumble(self):
336 if ( self.sk >= 100 ):
337 fum = 0
338 else:
339 fum = (100 - self.sk )
340 final_fum = ( 100 - int( floor( fum/20 ) ) )
341 return ( self.sum() >= final_fum )
342
343 def __str__(self):
344
345 # get fumble roll result in case needed
346 fum_roll = random.randint(1,100)
347
348 # get special AP
349 spec_AP = int( floor ( self.AP * 1.5 ) )
350
351 # figure out +/- for modifer
352 strAdd="+"
353 swapmod= self.mod
354 if self.mod < 0:
355 strAdd= "-"
356 swapmod= -self.mod
357 modSum = self.sum()
358
359 # build output string
360 myStr = " (" + str(modSum) + ")"
361 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
362
363 if self.is_fumble():
364 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
365 elif self.is_critical() and self.is_riposte():
366 myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
367 myStr += " Riposte next SR"
368 elif self.is_critical():
369 myStr += " <b><font color=green>Critical!</font> All damage blocked!</b>"
370 elif self.is_special and self.is_riposte():
371 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
372 myStr += " Riposte next SR"
373 elif self.is_special():
374 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
375 elif self.is_success() and self.is_ma():
376 myStr += " <i><font color=green>Special!</font> Weapon/Shield AP [" + str(spec_AP) + "]</i>"
377 elif self.is_success():
378 myStr += " <font color=blue>Success!</font> Weapon/Shield AP [" + str(self.AP) + "]"
379 else:
380 myStr += " <font color=red>Failure!</font>"
381
382 Diff = self.sk - modSum
383 myStr += " </font>"
384
385 return myStr
386
387 # RQ Dodge Roll
388 #
389 # same as skill but with fumble dice and armor points
390 #
391 # [1d100.parry(50,0,0)]
392 # skill%, modifer, ma%
393 #
394
395 class rqdodge(std):
396 def __init__(self,source=[],sk=11,mod=0,ma=0,AP=0):
397 std.__init__(self,source)
398 self.sk = sk
399 self.mod = mod
400 self.ma = ma
401 self.AP = AP
402
403 def is_success(self):
404 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
405
406 def is_special(self):
407 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
408
409 def is_ma(self):
410 return (self.sum() <= self.ma)
411
412 def is_riposte(self):
413 return (self.sum() <= (self.ma / 5))
414
415 def is_critical(self):
416 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
417
418 def is_fumble(self):
419 if ( self.sk >= 100 ):
420 fum = 0
421 else:
422 fum = (100 - self.sk )
423 final_fum = ( 100 - int( floor( fum/20 ) ) )
424 return ( self.sum() >= final_fum )
425
426 def __str__(self):
427
428 # get fumble roll result in case needed
429 fum_roll = random.randint(1,100)
430
431 # get special AP
432 spec_AP = int( floor ( self.AP * 1.5 ) )
433
434 # figure out +/- for modifer
435 strAdd="+"
436 swapmod= self.mod
437 if self.mod < 0:
438 strAdd= "-"
439 swapmod= -self.mod
440 modSum = self.sum()
441
442 # build output string
443 myStr = " (" + str(modSum) + ")"
444 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
445
446 if self.is_fumble():
447 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
448 elif self.is_critical() and self.is_riposte():
449 myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
450 myStr += " Riposte on next SR"
451 elif self.is_critical():
452 myStr += " <b><font color=green>Critical!</font> All damage dodged!</b>"
453 elif self.is_special and self.is_riposte():
454 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
455 myStr += " Riposte on next SR"
456 elif self.is_special():
457 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
458 elif self.is_success() and self.is_ma():
459 myStr += " <i><font color=green>Special!</font> Damage dodged</b>"
460 elif self.is_success():
461 myStr += " <font color=blue>Success!</font> Damage dodged</b>"
462 else:
463 myStr += " <font color=red>Failure!</font>"
464
465 Diff = self.sk - modSum
466 myStr += " </font>"
467
468 return myStr
469
470
471
472 #
473 # RQ Attack Roll
474 #
475 # same as skill but with fumble dice and armor points
476 #
477 # [1d100.attack(50,0,0,2,9,3,1)]
478 # skill%, modifer, ma%, min weap dam, max weap dam, dam bonus, truesword_enabled
479 #
480 class rqattack(std):
481 def __init__(self,source=[],sk=11,mod=0,ma=0,mindam=0,maxdam=0,bondam=0,trueswd=0):
482 std.__init__(self,source)
483 self.sk = sk
484 self.mod = mod
485 self.ma = ma
486 self.mindam = mindam
487 self.maxdam = maxdam
488 self.bondam = bondam
489 self.trueswd = trueswd
490
491 def is_success(self):
492 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
493
494 def is_ma(self):
495 return (self.sum() <= self.ma)
496
497 def is_special(self):
498 return (self.sum() <= int(floor((self.sk + self.mod) / 5)))
499
500 def is_critical(self):
501 return ((self.sum() <= int(floor((self.sk + self.mod) / 20))))
502
503 def is_supercritical(self):
504 return (self.sum() == 1)
505
506 def is_fumble(self):
507 if ( self.sk >= 100 ):
508 fum = 0
509 else:
510 fum = (100 - self.sk )
511 final_fum = ( 100 - int( floor( fum/20 ) ) )
512 return ( self.sum() >= final_fum )
513
514 def __str__(self):
515
516 # get fumble roll result in case needed
517 fum_roll = random.randint(1,100)
518
519 # get hit location roll result in case needed
520 location = random.randint(1,20)
521 myStr = " to the ["+ str(location) + "] "
522 if location < 5:
523 myStr += "<B>Right Leg</B>"
524 elif location < 9:
525 myStr += "<B>Left Leg</B>"
526 elif location < 12:
527 myStr += "<B>Abdomen</B>"
528 elif location < 13:
529 myStr += "<B>Chest</B>"
530 elif location < 16:
531 myStr += "<B>Right Arm</B>"
532 elif location < 19:
533 myStr += "<B>Left Arm</B>"
534 else:
535 myStr += "<B>Head</B>"
536 hit_loc = myStr
537
538
539 # get normal damage in case needed
540 norm_damage = random.randint(self.mindam*(self.trueswd+1),self.maxdam*(self.trueswd+1)) + self.bondam
541 norm_damage_string = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
542 norm_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.bondam)
543 norm_damage_string += "}[" + str(norm_damage) + "] "
544
545 # get special/critical damage in case needed
546 crit_damage = random.randint( self.mindam*(self.trueswd+2), self.maxdam*(self.trueswd+2) ) + self.bondam
547 crit_damage_string = "{" + str( self.mindam*(self.trueswd+2) ) + "-" + str(self.maxdam*(self.trueswd+2)) + "+" + str(self.bondam) + "}[" + str(crit_damage) + "] "
548
549 # get supercritical damage in case needed
550 super_damage = norm_damage + self.maxdam
551 super_damage_string = "{" + str( self.mindam*(self.trueswd+1) ) + "-"
552 super_damage_string += str(self.maxdam*(self.trueswd+1)) + "+" + str(self.maxdam)
553 super_damage_string += "+" + str(self.bondam) + "}[" + str(super_damage) + "] "
554
555 # figure out +/- for modifer
556 strAdd="+"
557 swapmod= self.mod
558 if self.mod < 0:
559 strAdd= "-"
560 swapmod= -self.mod
561 modSum = self.sum()
562
563 # build output string
564 myStr = " (" + str(modSum) + ")"
565 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
566
567 if self.is_fumble():
568 myStr += " <b><font color=red>Fumble!</font> See Fumble Chart [" + str(fum_roll) + "]</b>"
569 elif (self.is_supercritical() and self.is_success()):
570 myStr += " <b><font color=green>Super Critical!</font></b> Damage: " + str(super_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
571 elif (self.is_critical() and self.is_success()):
572 myStr += " <b><font color=green>Critical!</font></b> Damage: " + str(crit_damage_string) + "<u>No Armor Stops</u>" + str(hit_loc)
573 elif ( self.is_special() and self.is_success() ):
574 myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
575 elif (self.is_success() and self.is_ma()):
576 myStr += " <i><font color=green>Special!</font></i> Damage: " + str(crit_damage_string) + str(hit_loc)
577 elif self.is_success():
578 myStr += " <font color=blue>Success!</font> Damage: " + str(norm_damage_string) + str(hit_loc)
579 else:
580 myStr += " <font color=red>Failure!</font>"
581
582 return myStr
583
584 #
585 #
586 # Sorcery Roll: [1d100.sorcery(90, 10, 5, 4, 3, 2, 1)]
587 # (sk, mod, pow, cer, int, acc, mlt)
588 #
589 # Ceremony: (+1d6% per strike rank spent on ceremony)
590 # Intensity: (-3% per point of Intensity)
591 # Duration: (-4% per point of Duration)
592 # Range: (-5% per point of Range)
593 # Multispell: (-10% per each spell over 1)
594 # Acceleration: (-5% per point of Acceleration)
595 # Hold: (-2% per point in spell Held)
596 #
597 class rqsorcery(std):
598 def __init__(self,source=[],sk=11,mod=0,pow=0,cer=0,int=0,acc=0,mlt=0):
599 std.__init__(self,source)
600 self.sk = sk # sorcery skill
601 self.mod = mod # additional modifier ( from duration, range, etc )
602 self.pow = pow # boost pow and additional pow ( from duration, range, etc )
603 self.cer = cer # ceremony d6
604 self.int = int # intensity ( -3% )
605 self.acc = acc # accelerate ( -5% )
606 self.mlt = mlt # multispell ( -10% )
607
608 def is_success(self):
609 return (((self.sum() <= (self.sk + self.mod)) or (self.sum() <= 5)) and (self.sum() <= 95))
610
611 def is_special(self):
612 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/5 ) ) ) )
613
614 def is_critical(self):
615 return ( ( self.sum() <= int( floor( ( self.sk + self.mod )/20 ) ) ) )
616
617 def is_fumble(self):
618 if ( self.sk >= 100 ):
619 fum = 0
620 else:
621 fum = (100 - self.sk )
622 final_fum = ( 100 - int( floor( fum/20 ) ) )
623 return ( self.sum() >= final_fum )
624
625 def __str__(self):
626
627 # get fumble roll result in case needed
628 fum_roll = random.randint(2,12)
629 if fum_roll == 12 :
630 fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each day to remember.</font>"
631 if fum_roll == 11 :
632 fum_string = "<br /><font color=purple>Caster temporarily forgets spell. Make an INTx5 roll each hour to remember. </font>"
633 if fum_roll == 10 :
634 fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect. </font>"
635 if fum_roll == 9 :
636 fum_string = "<br /><font color=purple>Caster is Stunned. Roll INTx3 to recover at SR 10 each round. </font>"
637 if fum_roll == 8 :
638 fum_string = "<br /><font color=purple>Caster takes 2D6 Damage to THP </font>"
639 if fum_roll == 7 :
640 fum_string = "<br /><font color=purple>Spell produces reverse of the intended effect at 2x Intensity. </font>"
641 if fum_roll == 6 :
642 fum_string = "<br /><font color=purple>Spell is cast on companions (if harmful) or on random nearby foes (if beneficial) </font>"
643 if fum_roll == 5 :
644 fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to Head </font>"
645 if fum_roll == 4 :
646 fum_string = "<br /><font color=purple>Spell is cast on caster (if harmful) or on random nearby foe (if beneficial) </font>"
647 if fum_roll == 3 :
648 fum_string = "<br /><font color=purple>Caster takes 1d6 Damage to THP </font>"
649 if fum_roll == 2 :
650 fum_string = "<br /><font color=purple>Caster takes 1 point of Damage to Head </font>"
651
652 # roll ceremony
653 ceremony_roll = random.randint( self.cer, (self.cer*6) )
654
655 # subtract manipulations
656 extra_mod = self.mod
657 self.mod += ceremony_roll - self.int*3 - self.acc*5 - self.mlt*10
658
659 # add up power cost
660 extra_pow = self.pow
661 self.pow += self.int + self.mlt + self.acc
662 special_pow = int( floor( ( self.pow )/2 ) )
663
664 # figure out +/- for modifer
665 strAdd="+"
666 swapmod= self.mod
667 if self.mod < 0:
668 strAdd= "-"
669 swapmod= -self.mod
670 modSum = self.sum()
671
672 # build output string
673 myStr = " (" + str(modSum) + ")"
674 myStr += " vs [" + str(self.sk) + strAdd + str(swapmod) + "]"
675
676 if self.is_fumble():
677 myStr += " <b><font color=red>Fumble!</font> POW Cost: [" + str(self.pow) + "],</b> " + fum_string
678 elif self.is_critical():
679 myStr += " <b><font color=green>Critical!</font></b> POW Cost: [1] "
680 elif self.is_special():
681 myStr += " <i><font color=green>Special!</font></i> POW Cost: [" + str(special_pow) + "] "
682 elif self.is_success():
683 myStr += " <font color=blue>Success!</font> POW Cost: [" + str(self.pow) + "] "
684 else:
685 myStr += " <font color=red>Failure!</font> POW Cost: [1]"
686
687 # print spell details
688 myStr += "<br /> --- Other Modifiers:[" + str( extra_mod ) + "], "
689 myStr += "Extra POW:[" + str( extra_pow ) + "], "
690 myStr += "Ceremony:[+" + str( ceremony_roll ) + "%], "
691 myStr += "Intensity(-3):[" + str( self.int ) + "], "
692 myStr += "Accelerate(-5):[" + str( self.acc ) + "], "
693 myStr += "Multispell(-10):[" + str( self.mlt ) + "] ---"
694
695 return myStr
696