gwdamcalc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|