gwdamcalc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/gwdamcalc +3 -0
- data/bin/gwdamcalc.rb +3 -0
- data/lib/gwdamcalc.rb +628 -0
- data/lib/test_gwdamcalc.rb +104 -0
- data/license +23 -0
- data/readme +48 -0
- metadata +67 -0
data/bin/gwdamcalc
ADDED
data/bin/gwdamcalc.rb
ADDED
data/lib/gwdamcalc.rb
ADDED
@@ -0,0 +1,628 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2007 Daniel Stevens
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person
|
6
|
+
# obtaining a copy of this software and associated documentation
|
7
|
+
# files (the "Software"), to deal in the Software without
|
8
|
+
# restriction, including without limitation the rights to use,
|
9
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the
|
11
|
+
# Software is furnished to do so, subject to the following
|
12
|
+
# conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
#++
|
26
|
+
# = gwdamcalc - The Guild Wars Damage Calculator
|
27
|
+
#
|
28
|
+
# _gwdamcalc_ is a damage calculator for the MMORPG/CORPG video game Guild
|
29
|
+
# Wars. The software can be used to determine the damage caused by
|
30
|
+
# a single attack by a character against a defending target, given a set of
|
31
|
+
# relevant statistics for the attacker and target. The implementation for the
|
32
|
+
# software was inspired by Guild Wars damage research documented at
|
33
|
+
# http://guildwars.incgamers.com/wiki/index.php/Damage_Explained and other
|
34
|
+
# sources.
|
35
|
+
#
|
36
|
+
# == Downloading
|
37
|
+
#
|
38
|
+
# The latest version of _gwdamcalc_ can be downloaded from http://rubyforge.org/frs/?group_id=4975.
|
39
|
+
#
|
40
|
+
# == Requirements
|
41
|
+
#
|
42
|
+
# _gwdamcalc_ is implemented in the scripting language _Ruby_. The Ruby
|
43
|
+
# interpreter is require in order to run the script and use the software.
|
44
|
+
# Information on downloading the Ruby interpreter for you platform is available at
|
45
|
+
# http://www.ruby-lang.org/en/downloads.
|
46
|
+
#
|
47
|
+
# == Usage
|
48
|
+
#
|
49
|
+
# _gwdamcalc_ is invoked from the command line, passing the statistics of the
|
50
|
+
# attacker and target as arguments. If gwdamcalc was installed from a gem, it
|
51
|
+
# should be possible to invoke it directly from the command line from any
|
52
|
+
# directory. Use the <tt>--help</tt> argument to see a list of arguments and
|
53
|
+
# their usage. Additional information can be found in the Rdoc for the
|
54
|
+
# following classes:
|
55
|
+
#
|
56
|
+
# GWTools::DamageCalc:: This contains detailed information on the workings of
|
57
|
+
# _gwdamcalc_. Read this if you're interested in using
|
58
|
+
# _gwdamcalc_ with your own code.
|
59
|
+
# GWTools::UI:: This contains more detailed information about _gwdamcalc_'s
|
60
|
+
# command line interface. Read this if you're having trouble
|
61
|
+
# figuring out how to use it.
|
62
|
+
#
|
63
|
+
# == License information
|
64
|
+
#
|
65
|
+
# Author:: Dan Stevens <dan.stevens.iamai@googlemail.com>
|
66
|
+
# License:: Copyright (c) 2007 Daniel Stevens. Released under a MIT/X11 style
|
67
|
+
# license. See the 'license' file.
|
68
|
+
#
|
69
|
+
# == Warranty
|
70
|
+
#
|
71
|
+
# This software is provided "as is" and without any express or
|
72
|
+
# implied warranties, including, without limitation, the implied
|
73
|
+
# warranties of merchantibility and fitness for a particular
|
74
|
+
# purpose.
|
75
|
+
#
|
76
|
+
|
77
|
+
require 'optparse'
|
78
|
+
require 'ostruct'
|
79
|
+
|
80
|
+
module GWTools
|
81
|
+
|
82
|
+
# A basic damage calculator for the MMORPG/CORPG video
|
83
|
+
# game <em>Guild Wars</em>. The class is based strongly around the damage
|
84
|
+
# calculation itself: only the relevant independent variables are expected, as
|
85
|
+
# opposed to them being encapsulated into classes that represent attack/target
|
86
|
+
# entities in an abstract form (this may be a future development).
|
87
|
+
#
|
88
|
+
# The class has been mostly derived from the contents of
|
89
|
+
# http://guildwars.incgamers.com/wiki/index.php/Damage_Explained. The
|
90
|
+
# calculation has been divided into a number of methods that reflect most of the
|
91
|
+
# components mentioned in the article, although most of the names of the terms
|
92
|
+
# have been changed.
|
93
|
+
#
|
94
|
+
# The Full equation for spell, signet, staff and wand attacks:
|
95
|
+
# * d = (bd � tda � (2 ^ (((3 � lvl) - (ttav � tap)) � 40))) + db
|
96
|
+
# The Full equation for <em>Martial Weapon</em> attacks:
|
97
|
+
# * d = (bd � tda � (2 ^ (((5 � min((lvl + 4) � 2 rank) + 2 � max(0, rank - ((lvl + 4) � 2))) - (ttav � tap)) � 40))) + db
|
98
|
+
class DamageCalc
|
99
|
+
|
100
|
+
# Version for gwdamcalc
|
101
|
+
VERSION = '0.1.0'
|
102
|
+
|
103
|
+
# PHYS_DAM_TYPES = [:blunt, :slashing, :piercing].freeze
|
104
|
+
|
105
|
+
# The set of weapon types that are classified as <em>martial weapons</em>.
|
106
|
+
MARTIAL_WEAPONS = [:axe, :bow, :daggers, :hammer, :scythe, :spear, :sword].freeze
|
107
|
+
|
108
|
+
# All weapon types.
|
109
|
+
WEAPONS = (MARTIAL_WEAPONS + [:staff, :wand, :spell, :signet]).freeze
|
110
|
+
|
111
|
+
# A regular expression that matches strings that express the damage range of
|
112
|
+
# a weapons in the form that is used in Guild Wars e.g. '11-25'.
|
113
|
+
BD_FORM = /(\d+)(-(\d+))?/.freeze
|
114
|
+
|
115
|
+
# call-seq: tofrac(percentage) -> Float
|
116
|
+
#
|
117
|
+
# Converts a value as a percentage (integer) into the fractional equivalent.
|
118
|
+
# Examples:
|
119
|
+
#
|
120
|
+
# DamageCalc.tofrac(20) -> 1.25
|
121
|
+
# DamageCalc.tofrac(-12) -> 0.88
|
122
|
+
def DamageCalc.tofrac(percent)
|
123
|
+
(100 + percent) / 100.0
|
124
|
+
end
|
125
|
+
|
126
|
+
# call-seq: topercent(fraction) -> Integer
|
127
|
+
#
|
128
|
+
# Converts a value as a fraction (float) into the equivalent percentage (and
|
129
|
+
# are rounded, if necessary).
|
130
|
+
# Examples:
|
131
|
+
#
|
132
|
+
# DamageCalc.topercent(1.25) -> 20
|
133
|
+
# DamageCalc.topercent(0.88) -> -12
|
134
|
+
def DamageCalc.topercent(fraction)
|
135
|
+
(fraction * 100 - 100).round
|
136
|
+
end
|
137
|
+
|
138
|
+
# The type of weapon causing the damage (:axe, :bow, :daggers, :hammer,
|
139
|
+
# :scythe, :spear, :sword, :staff, :wand, :spell, :signet). If the attack is
|
140
|
+
# caused by a spell or signet, use the symbols :spell and :signet
|
141
|
+
# respectively.
|
142
|
+
attr_accessor :wep_type
|
143
|
+
|
144
|
+
# The attacker's rank in the relevant skill attribute for the weapon. Not
|
145
|
+
# applicable for attacks caused by spells, signets, staves or wands.
|
146
|
+
attr_accessor :rank
|
147
|
+
|
148
|
+
# The attacker's level.
|
149
|
+
attr_accessor :lvl
|
150
|
+
|
151
|
+
# The <em>Base Damage</em> range of the weapon, or damage value of the skill.
|
152
|
+
# If a Range object is specified, a value from within the range is chosen
|
153
|
+
# automatically at random. A single value will be used outright.
|
154
|
+
attr_accessor :bd
|
155
|
+
|
156
|
+
# The <em>Total Damage Adjustment</em> for the weapon. This should be
|
157
|
+
# expressed as a fraction, with values greater than one for a positive
|
158
|
+
# adjustment and values between 0.0 and 0.99 for a negative adjustment e.g.
|
159
|
+
# +20% damage = 1.20, -15% damage = 0.85. Summate adjustments from multiple
|
160
|
+
# sources into this variable. Use the tofrac method convert whole percentage
|
161
|
+
# into fractions.
|
162
|
+
attr_accessor :tda
|
163
|
+
|
164
|
+
# The <em>Total Target Armor Value</em>. The sum of all the sources of
|
165
|
+
# armor for the target including body armor, shields (where appropriate),
|
166
|
+
# armor buffs and debuffs from skills (debuffs should have negative impact on
|
167
|
+
# the value).
|
168
|
+
attr_accessor :ttav
|
169
|
+
|
170
|
+
# The <em>Total Armor Penetration</em> of the attack. This should be
|
171
|
+
# expressed as a fraction, with the armor penetration acting as a reduction
|
172
|
+
# in the target's armor by multiplying it against the ttav. Therefore, the
|
173
|
+
# value of this variable should be between 0.0 (for complete penetration) up
|
174
|
+
# to 1.0 for no penetration. When using the tofrac method, specify the armor
|
175
|
+
# penetration as a negative number and the appropriate fraction will be
|
176
|
+
# returned.
|
177
|
+
attr_accessor :tap
|
178
|
+
|
179
|
+
# The <em>Damage Bonus</em> of the attack; additional damage which is added
|
180
|
+
# at the end of the <em>Net Damage</em> calculation.
|
181
|
+
attr_accessor :db
|
182
|
+
|
183
|
+
# call-seq:
|
184
|
+
# new(wep_type=:sword, bd=11..15, ttav=60, lvl=20, rank=12, tda=1.0, tap=1.0, db=0) -> DamageCalc
|
185
|
+
#
|
186
|
+
# Constructs a new DamageCalc object. Accepts the attributes defined above
|
187
|
+
# as parameters.
|
188
|
+
def initialize(wep_type=:sword, bd=11..25, ttav=60, lvl=20, rank=12, tda=1.0,
|
189
|
+
tap=1.0, db=0)
|
190
|
+
@wep_type = wep_type
|
191
|
+
@bd = bd
|
192
|
+
@ttav = ttav
|
193
|
+
@lvl = lvl
|
194
|
+
@rank = rank
|
195
|
+
@tda = tda
|
196
|
+
@tap = tap
|
197
|
+
@db = db
|
198
|
+
end
|
199
|
+
|
200
|
+
# call-seq: d -> Integer
|
201
|
+
#
|
202
|
+
# Returns the <em>Net Damage</em> (d); the final resultant damage taking
|
203
|
+
# into the account the attacker's stats and the target's armor. It is
|
204
|
+
# calculated as the product of the <em>Base Damage</em> (bd), the
|
205
|
+
# <em>Total Damage Adjustment</em> (tda) and the <em>Defensive
|
206
|
+
# Adjustment</em> (da), plus a <em>Damage Bonus</em> (db):
|
207
|
+
#
|
208
|
+
# d = (bd � tda � da) + db
|
209
|
+
#
|
210
|
+
# The end result is rounded to the nearest integer.
|
211
|
+
def d
|
212
|
+
((bd.pick * tda * da) + db).round
|
213
|
+
end
|
214
|
+
|
215
|
+
# Alias for d
|
216
|
+
alias calc d
|
217
|
+
|
218
|
+
# call-seq: da -> Float
|
219
|
+
#
|
220
|
+
# Returns the <em>Defensive Adjustment</em> (da); a fraction that modifies
|
221
|
+
# damage with respect to the attacker's stance and targets armor. It is
|
222
|
+
# calculated as follows:
|
223
|
+
#
|
224
|
+
# 2^((atddm - eav) � 40)
|
225
|
+
#
|
226
|
+
# where:
|
227
|
+
# * <b>atddm</b> is the <em>Attack Type Dependant Damage Modifier</em>;
|
228
|
+
# * <b>eav</b> is the <em>Effective Armor Value</em> of the target.
|
229
|
+
def da
|
230
|
+
2 ** ((atddm - eav) / 40.0)
|
231
|
+
end
|
232
|
+
|
233
|
+
# call-seq: atddm -> Integer
|
234
|
+
#
|
235
|
+
# Returns the <em>Attack Type Dependant Damage Modifier</em> (atddm). The
|
236
|
+
# value returned depends on the type of attack, which are attacks made with a
|
237
|
+
# martial weapon or attacks caused by a skill, staff or wand. The values
|
238
|
+
# <em>Damage Modified for Weapon Attacks</em> (dmwa) or <em>Damage Modified
|
239
|
+
# for Spell Attacks</em> (dmsa) will be returned, respectively.
|
240
|
+
def atddm
|
241
|
+
martial? ? dmwa : dmsa
|
242
|
+
end
|
243
|
+
|
244
|
+
# call-seq: martial? -> true or false
|
245
|
+
#
|
246
|
+
# Returns true if the attack is caused by a martial weapon i.e. axe, sword,
|
247
|
+
# daggers, hammer, scythe, spear, bow.
|
248
|
+
#
|
249
|
+
def martial?
|
250
|
+
MARTIAL_WEAPONS.include? wep_type
|
251
|
+
end
|
252
|
+
|
253
|
+
# call-seq: dmwa -> Integer or Float
|
254
|
+
#
|
255
|
+
# Returns the <em>Damage Modifier for Weapon Attacks</em> (dmwa); the
|
256
|
+
# modification made to the damage for attacks made with martial weapons.
|
257
|
+
# There is a threshold, dependant upon the level of the attacker, at which
|
258
|
+
# the rank for the weapon has a lesser influence when exceeding the
|
259
|
+
# threshold. dmwa is calculated as follows:
|
260
|
+
#
|
261
|
+
# 5 � min(threshold, rank) + 2 � max(0, rank - threshold)
|
262
|
+
def dmwa
|
263
|
+
5 * [threshold, rank].min + 2 * [0, rank - threshold].max
|
264
|
+
end
|
265
|
+
|
266
|
+
# call-seq: threshold -> Float
|
267
|
+
#
|
268
|
+
# Returns the level dependant threshold past which the influence the rank has
|
269
|
+
# on the damage modifier is lower. It is calculated as follows:
|
270
|
+
#
|
271
|
+
# threshold = (lvl + 4) � 2
|
272
|
+
def threshold
|
273
|
+
(lvl + 4) / 2.0
|
274
|
+
end
|
275
|
+
|
276
|
+
# call-seq: dmsa -> Integer
|
277
|
+
#
|
278
|
+
# Returns the <em>Damage Modifier for Spell Attacks</em> (dmsa); the
|
279
|
+
# modification made to the damage for attacks made with spells, signets,
|
280
|
+
# staves or wands. It is calculated as follows:
|
281
|
+
#
|
282
|
+
# 3 � <em>Attacker's Level</em>
|
283
|
+
def dmsa
|
284
|
+
3 * lvl
|
285
|
+
end
|
286
|
+
|
287
|
+
# call-seq: eav -> Float
|
288
|
+
#
|
289
|
+
# Returns the <em>Effective Armor Value</em> (eav) of the target; the product
|
290
|
+
# of the effective armor of the target taking into account its own total
|
291
|
+
# armor value (ttav) and the <em>Total Armor Penetration</em>
|
292
|
+
# of the attacker:
|
293
|
+
#
|
294
|
+
# ttav � tap
|
295
|
+
def eav
|
296
|
+
ttav * tap
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
# The following describes the command line interface for _gwdamcalc_ in more detail.
|
302
|
+
#
|
303
|
+
# == Invoking gwdamcalc
|
304
|
+
#
|
305
|
+
# If gwdamcalc was installed from a gem , it can be invoked directly from
|
306
|
+
# the command line from any directory:
|
307
|
+
#
|
308
|
+
# gwdamcalc
|
309
|
+
#
|
310
|
+
# If you did not install from a gem, you will need to locate the gwdamcalc.rb
|
311
|
+
# file, change the working directory to that of the file and enter the
|
312
|
+
# following in your command shell:
|
313
|
+
#
|
314
|
+
# ruby gwdamcalc.rb
|
315
|
+
#
|
316
|
+
# == Usage
|
317
|
+
#
|
318
|
+
# The damage calculation for Guild Wars depends on a set of statistics relating
|
319
|
+
# the attacking and defending characters. _gwdamcalc_ has a set of command line
|
320
|
+
# options that can be used to specify the value of these statistics for use in
|
321
|
+
# the calculation. If a option is not specified for a stat, a default value is a
|
322
|
+
# assumed in the calculation. You can get _gwdamcalc_ to list the set of
|
323
|
+
# statistics and their default values by using the <tt>--help</tt> arguments:
|
324
|
+
#
|
325
|
+
# $ gwdamcalc --help
|
326
|
+
# Usage: gwdamcalc [OPTIONS]...
|
327
|
+
# A basic damage calculator for the MMORPG/CORPG video game Guild Wars. The
|
328
|
+
# independent variables of the calculation are specified by the options below.
|
329
|
+
# See the rdoc for more details on each of the variables.
|
330
|
+
#
|
331
|
+
# gwdamcalc accepts one or more of the options below. If a option is not
|
332
|
+
# explicitely specified, the default value is assumed in the calculation.
|
333
|
+
# -w, --weptype=string The type of weapon. Choose from: axe, bow, sword, daggers, hammer,
|
334
|
+
# scythe, spear, staff, wand. If the attack is caused by a spell or
|
335
|
+
# signet, use 'spell' and 'signet' respectively. Default
|
336
|
+
# value: sword
|
337
|
+
# -d, --bd=int[-int] The Base Damage of the attack. Specified or a single value, or a
|
338
|
+
# range in the form 11-22. Default value: 11-25
|
339
|
+
# -a, --ttav=int The Total Target Armor Value. Default value: 60
|
340
|
+
# -l, --lvl=int The level of the attacker. Default value: 20
|
341
|
+
# -r, --rank=int The attacker's rank in the appropriate attribute for their weapon.
|
342
|
+
# Not required for attacks made with spells, signets, staves and wands.
|
343
|
+
# Default value: 12
|
344
|
+
# -j, --tda=float The Total Damage Adjustment. Expressed as a fraction (see rdoc).
|
345
|
+
# Default value: 1.0
|
346
|
+
# -p, --tap=float The Total Armor Penetration. Expressed as a fraction (see rdoc).
|
347
|
+
# Default value: 1.0
|
348
|
+
# -b, --db=int The Damage Bonus. Default value: 0
|
349
|
+
# -s, --summary Display a summary of the values of the variables of the calculation
|
350
|
+
# -q, --quiet Displays only the result of the calculation
|
351
|
+
# --help, --usage Displays this help message.
|
352
|
+
# --version Displays version information.
|
353
|
+
#
|
354
|
+
# The first eight options are for specifying values relating to the stats of the
|
355
|
+
# attacker and defender. The last four are support options. Each option has a
|
356
|
+
# short, single character version, prefixed with a single dash, and long
|
357
|
+
# version prefixd with two dashs. When specify a value using the short version,
|
358
|
+
# seperate the option and the value with a space, for example:
|
359
|
+
#
|
360
|
+
# gwdamcalc -d 50
|
361
|
+
#
|
362
|
+
# When specify a value using the long version, seperate the option and the value
|
363
|
+
# with an equals sign, for example:
|
364
|
+
#
|
365
|
+
# gwdamcalc --bd=50
|
366
|
+
#
|
367
|
+
# The following headings describe each of the options in more detail, in the above
|
368
|
+
# order.
|
369
|
+
#
|
370
|
+
# === Weapon type
|
371
|
+
#
|
372
|
+
# -w, --weptype=string
|
373
|
+
#
|
374
|
+
# Use this specify the means by which the attacker is attacking. Technically, in
|
375
|
+
# terms of how this value affects the calculation, there are two groups: 'Martial
|
376
|
+
# weapons', which include axe, bow, sword, dagger, hammer, scythe and spear, and
|
377
|
+
# 'magic', which include staff, wand, spell and signet. Changing the weapon type
|
378
|
+
# to another in the same group does not affect the calculation in anyway.
|
379
|
+
#
|
380
|
+
# === Base damage
|
381
|
+
#
|
382
|
+
# -d, --bd=int[-int]
|
383
|
+
#
|
384
|
+
# Use this to specify the damage rating for the weapon or skill. This can be
|
385
|
+
# discreet value or a range. If a range is specified, a whole value from within the
|
386
|
+
# range will be selected from within the range. If you are performing a
|
387
|
+
# calculation for a martial weapon, which typically have a range for its damage
|
388
|
+
# rating, you can set this value to its minimum or maximum value (or any value
|
389
|
+
# you want!) to get the minimum or maximum possible damage for the given
|
390
|
+
# remaining stats.
|
391
|
+
#
|
392
|
+
# If specifying a range, seperate the lower and upper values of the range with a
|
393
|
+
# dash, for example:
|
394
|
+
#
|
395
|
+
# gwdamcalc -bd 11-22
|
396
|
+
#
|
397
|
+
# === Total Target Armor Value
|
398
|
+
#
|
399
|
+
# -a, --ttav=int
|
400
|
+
#
|
401
|
+
# The <em>Total Target Armor Value</em> is the sum of all the sources of armor for the target
|
402
|
+
# including body armor, shields (where appropriate), armor buffs and debuffs from
|
403
|
+
# skills (debuffs should have negative impact on the value).
|
404
|
+
#
|
405
|
+
# === Level of attacker
|
406
|
+
#
|
407
|
+
# -l, --lvl=int
|
408
|
+
#
|
409
|
+
# Use this to specify the level of the attacker.
|
410
|
+
#
|
411
|
+
# === The attacker's rank
|
412
|
+
#
|
413
|
+
# Use this to specify the attacker's rank in the relevant skill attribute for the
|
414
|
+
# weapon. This is only relevant to attacks made with martial weapons.
|
415
|
+
#
|
416
|
+
# === Total Damage Adjustment
|
417
|
+
#
|
418
|
+
# Use this to specify a fractional modification of the base damage. Instances of
|
419
|
+
# where this would be used is where the weapon has +% damage modifier (e.g. +20%
|
420
|
+
# damage for a customized weapon). However this option expects this value as a
|
421
|
+
# fraction rather than a percentage, with values greater than one for a positive
|
422
|
+
# adjustment and values between 0.0 and 0.99 for a negative adjustment. If there
|
423
|
+
# are multiple damage modifies, total them together.
|
424
|
+
#
|
425
|
+
# Tip: If you don't want to convert a percentage into a fraction in your head,
|
426
|
+
# with Ruby installed you can enter the following in the command shell,
|
427
|
+
# replacing 'x' with the percentage, to get the fraction:
|
428
|
+
#
|
429
|
+
# ruby -e "puts (100 + x) / 100.0"
|
430
|
+
#
|
431
|
+
# === Total Armor Pentration
|
432
|
+
#
|
433
|
+
# Use this to specify the total of all sources of armor penetration against the
|
434
|
+
# target. Like the Total Damage Adjustment, with the armor penetration acting as a
|
435
|
+
# reduction in the target's armor by multiplying it against the Total Target Armor
|
436
|
+
# Value. Therefore, the value of this variable should be between 0.0 (for complete
|
437
|
+
# penetration) up to 1.0 for no penetration.
|
438
|
+
class UI
|
439
|
+
|
440
|
+
include GWTools
|
441
|
+
|
442
|
+
BANNER =
|
443
|
+
"Usage: gwdamcalc [OPTIONS]...
|
444
|
+
A basic damage calculator for the MMORPG/CORPG video game Guild Wars. The
|
445
|
+
independent variables of the calculation are specified by the options below.
|
446
|
+
See the rdoc for more details on each of the variables." # :nodoc:
|
447
|
+
|
448
|
+
WEP_TYPES = [:axe, :bow, :sword, :daggers, :hammer, :scythe, :spear, :staff,
|
449
|
+
:wand, :spell, :signet].freeze
|
450
|
+
|
451
|
+
def initialize
|
452
|
+
|
453
|
+
begin
|
454
|
+
|
455
|
+
@calc = DamageCalc.new()
|
456
|
+
@summary = false
|
457
|
+
@quiet = false
|
458
|
+
|
459
|
+
# Deal with command line paramters
|
460
|
+
parse(ARGV)
|
461
|
+
|
462
|
+
unless @quiet
|
463
|
+
if @summary
|
464
|
+
puts
|
465
|
+
puts "Calculation summary:"
|
466
|
+
print " Weapon type:\t\t\t", @calc.wep_type.id2name.capitalize, "\n"
|
467
|
+
print " Base Damage:\t\t\t", @calc.bd.begin, @calc.bd.is_a?(Range) ? "-#{@calc.bd.end}" : "", "\n"
|
468
|
+
print " Total Target Armor Value:\t", @calc.ttav, "\n"
|
469
|
+
print " Attacker's level:\t\t", @calc.lvl, "\n"
|
470
|
+
print " Attacker's rank:\t\t", @calc.rank, "\n"
|
471
|
+
printf " Total Damage Adjustment:\t%+d%% (%.2f)\n", DamageCalc.topercent(@calc.tda), @calc.tda
|
472
|
+
printf " Total Armor Penetration:\t%+d%% (%.2f)\n", DamageCalc.topercent(@calc.tap), @calc.tap, "\n"
|
473
|
+
print " Damage Bonus:\t\t\t", @calc.db, "\n"
|
474
|
+
end
|
475
|
+
|
476
|
+
puts
|
477
|
+
print "Calculated damage: "
|
478
|
+
end
|
479
|
+
|
480
|
+
puts @calc.d
|
481
|
+
|
482
|
+
rescue SystemCallError => err
|
483
|
+
$stderr.puts "Error: #{err}"
|
484
|
+
rescue OptionParser::InvalidArgument => err
|
485
|
+
$stderr.puts "Error: #{err}"
|
486
|
+
$stderr.puts "Please ensure option argument is in the correct format."
|
487
|
+
$stderr.puts "Use -h option for valid options and their argument's format."
|
488
|
+
rescue OptionParser::InvalidOption => err
|
489
|
+
$stderr.puts "Error: #{err}"
|
490
|
+
$stderr.puts "Use -h option for valid options."
|
491
|
+
end
|
492
|
+
|
493
|
+
end
|
494
|
+
|
495
|
+
# Returns a struct containing the options.
|
496
|
+
def parse(args) # :nodoc:
|
497
|
+
# Stores options
|
498
|
+
#opts = OpenStruct.new
|
499
|
+
|
500
|
+
OptionParser.new() do |optparser|
|
501
|
+
optparser.banner = BANNER
|
502
|
+
|
503
|
+
optparser.separator ""
|
504
|
+
optparser.separator "gwdamcalc accepts one or more of the options below. If a option is not"
|
505
|
+
optparser.separator "explicitely specified, the default value is assumed in the calculation."
|
506
|
+
|
507
|
+
optparser.on("-w", "--weptype=string", WEP_TYPES,
|
508
|
+
"The type of weapon. Choose from: axe, bow, sword, daggers, hammer,",
|
509
|
+
"scythe, spear, staff, wand. If the attack is caused by a spell or",
|
510
|
+
"signet, use 'spell' and 'signet' respectively. Default",
|
511
|
+
"value: sword") do |arg|
|
512
|
+
@calc.wep_type = arg
|
513
|
+
end
|
514
|
+
|
515
|
+
optparser.on("-d", "--bd=int[-int]",
|
516
|
+
"The Base Damage of the attack. Specified or a single value, or a",
|
517
|
+
"range in the form 11-22. Default value: 11-25") do |arg|
|
518
|
+
if arg =~ BD_FORM
|
519
|
+
if $3.nil?: @calc.bd = $1.to_i
|
520
|
+
else @calc.bd = $1.to_i..$3.to_i
|
521
|
+
end
|
522
|
+
else raise OptionParser::InvalidArgument
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
optparser.on("-a", "--ttav=int", Integer,
|
527
|
+
"The Total Target Armor Value. Default value: 60") do |arg|
|
528
|
+
@calc.ttav = arg
|
529
|
+
end
|
530
|
+
|
531
|
+
optparser.on("-l", "--lvl=int", Integer,
|
532
|
+
"The level of the attacker. Default value: 20") do |arg|
|
533
|
+
@calc.lvl = arg
|
534
|
+
end
|
535
|
+
|
536
|
+
optparser.on("-r", "--rank=int", Integer,
|
537
|
+
"The attacker's rank in the appropriate attribute for their weapon.",
|
538
|
+
"Not required for attacks made with spells, signets, staves and wands.",
|
539
|
+
"Default value: 12") do |arg|
|
540
|
+
@calc.rank = arg
|
541
|
+
end
|
542
|
+
|
543
|
+
optparser.on("-j", "--tda=float", Float,
|
544
|
+
"The Total Damage Adjustment. Expressed as a fraction (see rdoc).",
|
545
|
+
"Default value: 1.0") do |arg|
|
546
|
+
@calc.tda = arg
|
547
|
+
end
|
548
|
+
|
549
|
+
optparser.on("-p", "--tap=float", Float,
|
550
|
+
"The Total Armor Penetration. Expressed as a fraction (see rdoc).",
|
551
|
+
"Default value: 1.0") do |arg|
|
552
|
+
@calc.tap = arg
|
553
|
+
end
|
554
|
+
|
555
|
+
optparser.on("-b", "--db=int", Integer,
|
556
|
+
"The Damage Bonus. Default value: 0") do |arg|
|
557
|
+
@calc.db = arg
|
558
|
+
end
|
559
|
+
|
560
|
+
optparser.on("-s", "--summary",
|
561
|
+
"Display a summary of the values of the variables of the calculation") do |arg|
|
562
|
+
@summary = true
|
563
|
+
end
|
564
|
+
|
565
|
+
optparser.on("-q", "--quiet",
|
566
|
+
"Displays only the result of the calculation") do |arg|
|
567
|
+
@quiet = true
|
568
|
+
end
|
569
|
+
|
570
|
+
optparser.on_tail("--help", "--usage", "Displays this help message.") do
|
571
|
+
puts optparser
|
572
|
+
exit
|
573
|
+
end
|
574
|
+
|
575
|
+
optparser.on_tail("--version", "Displays version information.") do
|
576
|
+
puts "gwdamcalc #{DamageCalc::VERSION}"
|
577
|
+
exit
|
578
|
+
end
|
579
|
+
|
580
|
+
optparser.parse!(args)
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
|
585
|
+
|
586
|
+
end
|
587
|
+
|
588
|
+
end
|
589
|
+
|
590
|
+
class Integer
|
591
|
+
#class Fixnum
|
592
|
+
|
593
|
+
# Accommodate for duck typing.
|
594
|
+
def pick
|
595
|
+
self
|
596
|
+
end
|
597
|
+
|
598
|
+
# Accommodate for duck typing.
|
599
|
+
def begin
|
600
|
+
self
|
601
|
+
end
|
602
|
+
|
603
|
+
# Accommodate for duck typing.
|
604
|
+
def end
|
605
|
+
self
|
606
|
+
end
|
607
|
+
|
608
|
+
end
|
609
|
+
|
610
|
+
# call-seq: randran(min, max) -> Integer
|
611
|
+
#
|
612
|
+
# Returns a random number with in the range specified by min and max
|
613
|
+
# inclusively.
|
614
|
+
def randran(min, max)
|
615
|
+
rand(max + 1 - min) + min
|
616
|
+
end
|
617
|
+
|
618
|
+
class Range
|
619
|
+
|
620
|
+
# Randomly picks a value within the the boundries of the range, inclusively.
|
621
|
+
def pick
|
622
|
+
randran(self.begin, self.end)
|
623
|
+
end
|
624
|
+
|
625
|
+
end
|
626
|
+
|
627
|
+
GWTools::UI.new if $0 == __FILE__
|
628
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'test/unit'
|
3
|
+
require 'gwdamcalc'
|
4
|
+
|
5
|
+
include GWTools
|
6
|
+
|
7
|
+
# A set of tests for GWTools::DamageCalc, based on a number of examples from the
|
8
|
+
# web (that are assumed to be accurate). These are:
|
9
|
+
# * http://guildwars.incgamers.com/wiki/index.php/Damage_Explained#Examples
|
10
|
+
# * http://www.guildwarsguru.com/content/game-mechanics-id674.php
|
11
|
+
class TestDamageCalc < Test::Unit::TestCase
|
12
|
+
|
13
|
+
# A level 16 elementalist casts a fireball (71 damage) at a monk wearing the
|
14
|
+
# judge�s armor (60AL + 10AL vs physical). The monk has a defensive staff of
|
15
|
+
# defense (+10AL). The monk takes 48 fire damage.
|
16
|
+
def test1
|
17
|
+
result = DamageCalc.new(:spell, 71, 70, 16).d
|
18
|
+
assert_equal(48, result)
|
19
|
+
end
|
20
|
+
|
21
|
+
# A level 15 Elementalist butchering packs of level 7, 21 defense Charr with
|
22
|
+
# 69 damage, level 8 Fireballs. Each one you cast is going to deal 104.6
|
23
|
+
# (105).
|
24
|
+
def test2
|
25
|
+
result = DamageCalc.new(:spell, 69, 21, 15).d
|
26
|
+
assert_equal(105, result)
|
27
|
+
end
|
28
|
+
|
29
|
+
# A level 20 Ranger hunting level 28, 118 defense Rift Wardens in the Tombs.
|
30
|
+
# You have a customized, 15-28 Half Moon Bow, and a level 12 attribute to go
|
31
|
+
# with it. Minimum damage: 18.3 (18); Maximum damage: 34.2 (34).
|
32
|
+
# def test3
|
33
|
+
# result = DamageCalc.new(:bow, 15..28, 118, 12, 20, 1.2, 0.8).d
|
34
|
+
# assert((result >= 18) && (result <= 34))
|
35
|
+
# @summary << ["test3:", result]
|
36
|
+
# end
|
37
|
+
|
38
|
+
# Attacker level:: 20
|
39
|
+
# Weapon:: Sword 15-22 damage +20%
|
40
|
+
# Swordmanship rank:: 9
|
41
|
+
# Strength:: 0 (0% armor penetration)
|
42
|
+
# Target armor:: 60 points
|
43
|
+
# Expected minimum damage:: 14
|
44
|
+
# Expected maximum damage:: 20
|
45
|
+
def test4
|
46
|
+
result = DamageCalc.new(:sword, 15..22, 60, 20, 9, 1.2, 1.0).d
|
47
|
+
assert((result >= 14) && (result <= 20))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Attacker level:: 20
|
51
|
+
# Weapon:: Sword 15-22 damage +20%
|
52
|
+
# Swordmanship rank:: 12
|
53
|
+
# Strength:: 0 (0% armor penetration)
|
54
|
+
# Target armor:: 60 points
|
55
|
+
# Expected minimum damage:: 18
|
56
|
+
# Expected maximum damage:: 26
|
57
|
+
def test5
|
58
|
+
result = DamageCalc.new(:sword, 15..22, 60, 20, 12, 1.2, 1.0).d
|
59
|
+
assert((result >= 18) && (result <= 26))
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# Attacker level:: 6
|
64
|
+
# Spell:: Flare 22 damage (5 Fire Magic)
|
65
|
+
# Target armor:: 60 points
|
66
|
+
# Expected damage:: 11
|
67
|
+
def test6
|
68
|
+
result = DamageCalc.new(:spell, 22, 60, 6).d
|
69
|
+
assert_equal(11, result)
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# Attacker level:: 73
|
74
|
+
# Spell:: Flare 22 damage (5 Fire Magic)
|
75
|
+
# Target armor:: 60 points
|
76
|
+
# Expected damage:: 11
|
77
|
+
def test7
|
78
|
+
result = DamageCalc.new(:spell, 22, 60, 7).d
|
79
|
+
assert_equal(11, result)
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
# Attacker level:: 30
|
84
|
+
# Spell:: Deep Freeze 76 damage (12 Water Magic)
|
85
|
+
# Target armor:: 60 points
|
86
|
+
# Expected damage:: 128
|
87
|
+
def test8
|
88
|
+
result = DamageCalc.new(:spell, 76, 60, 30).d
|
89
|
+
assert_equal(128, result)
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
# Attacker level:: 10
|
94
|
+
# Weapon:: Wand 6-10 damage + 20%
|
95
|
+
# Target armor:: 60 points
|
96
|
+
# Expected Minimum damage:: 4
|
97
|
+
# Expected Maximum damage:: 7
|
98
|
+
def test9
|
99
|
+
result = DamageCalc.new(:wand, 6..10, 60, 10, nil, 1.2).d
|
100
|
+
assert((result >= 4) && (result <= 7))
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/license
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2007 Daniel Stevens
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/readme
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= gwdamcalc - The Guild Wars Damage Calculator
|
2
|
+
|
3
|
+
_gwdamcalc_ is a damage calculator for the MMORPG/CORPG video game Guild
|
4
|
+
Wars. The software can be used to determine the damage caused by
|
5
|
+
a single attack by a character against a defending target, given a set of
|
6
|
+
relevant statistics for the attacker and target. The implementation for the
|
7
|
+
software was inspired by Guild Wars damage research documented at
|
8
|
+
http://guildwars.incgamers.com/wiki/index.php/Damage_Explained and other
|
9
|
+
sources.
|
10
|
+
|
11
|
+
== Downloading
|
12
|
+
|
13
|
+
The latest version of _gwdamcalc_ can be downloaded from http://rubyforge.org/frs/?group_id=4975.
|
14
|
+
|
15
|
+
== Requirements
|
16
|
+
|
17
|
+
_gwdamcalc_ is implemented in the scripting language _Ruby_. The Ruby
|
18
|
+
interpreter is require in order to run the script and use the software.
|
19
|
+
Information on downloading the Ruby interpreter for you platform is available at
|
20
|
+
http://www.ruby-lang.org/en/downloads.
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
_gwdamcalc_ is invoked from the command line, passing the statistics of the
|
25
|
+
attacker and target as arguments. If gwdamcalc was installed from a gem, it
|
26
|
+
should be possible to invoke it directly from the command line from any
|
27
|
+
directory. Use the '--help' argument to see a list of arguments and their usage.
|
28
|
+
Additional information can be found in the Rdoc for the following classes:
|
29
|
+
|
30
|
+
GWTools::DamageCalc:: This contains detailed information on the workings of
|
31
|
+
_gwdamcalc_. Read this if you're interested in using
|
32
|
+
_gwdamcalc_ with your own code.
|
33
|
+
GWTools::UI:: This contains more detailed information about _gwdamcalc_'s
|
34
|
+
command line interface. Read this if you're having trouble
|
35
|
+
figuring out how to use it.
|
36
|
+
|
37
|
+
== License information
|
38
|
+
|
39
|
+
Author:: Dan Stevens <dan.stevens.iamai@googlemail.com>
|
40
|
+
License:: Copyright (c) 2007 Daniel Stevens. Released under a MIT/X11 style
|
41
|
+
license. See the 'license' file.
|
42
|
+
|
43
|
+
== Warranty
|
44
|
+
|
45
|
+
This software is provided "as is" and without any express or
|
46
|
+
implied warranties, including, without limitation, the implied
|
47
|
+
warranties of merchantibility and fitness for a particular
|
48
|
+
purpose.
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gwdamcalc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan 'IAmAI' Stevens
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-01-03 00:00:00 +00:00
|
13
|
+
default_executable: gwdamcalc.rb
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A basic damage calculator for the MMORPG/CORPG video game, Guild Wars.
|
17
|
+
email: dan.stevens.iamai@googlemail.com
|
18
|
+
executables:
|
19
|
+
- gwdamcalc.rb
|
20
|
+
- gwdamcalc
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- readme
|
25
|
+
- license
|
26
|
+
files:
|
27
|
+
- lib
|
28
|
+
- bin
|
29
|
+
- license
|
30
|
+
- readme
|
31
|
+
- lib/gwdamcalc.rb
|
32
|
+
- lib/test_gwdamcalc.rb
|
33
|
+
- bin/gwdamcalc
|
34
|
+
- bin/gwdamcalc.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://gwdamcalc.rubyforge.org
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --title
|
40
|
+
- Guild Wars Damage Calculator Documentation
|
41
|
+
- --main
|
42
|
+
- readme
|
43
|
+
- --inline-source
|
44
|
+
- --line-numbers
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project: gwdamcalc
|
62
|
+
rubygems_version: 1.0.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Guild Wars Damage Calculator
|
66
|
+
test_files:
|
67
|
+
- lib/test_gwdamcalc.rb
|