gemwarrior 0.15.9 → 0.15.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,836 +1,836 @@
1
- # lib/gemwarrior/evaluator.rb
2
- # Evaluates prompt input
3
-
4
- require_relative 'arena'
5
- require_relative 'game_assets'
6
- require_relative 'game_options'
7
-
8
- module Gemwarrior
9
- class Evaluator
10
- # CONSTANTS
11
- PROGRAM_NAME = 'Gem Warrior'
12
- QUIT_MESSAGE = 'Thanks for playing the game. Until next time...'
13
- RESUME_MESSAGE = 'Back to adventuring!'
14
-
15
- GO_PARAMS = 'Options: north, east, south, west'
16
- CHANGE_PARAMS = 'Options: name'
17
- DEBUG_LIST_PARAMS = 'Options: players, creatures, items, locations, monsters, weapons, armor'
18
- DEBUG_STAT_PARAMS = 'Options: hp_cur, atk_lo, atk_hi, experience, rox, strength, dexterity, defense, inventory'
19
-
20
- ERROR_COMMAND_INVALID = 'That is not something the game yet understands.'
21
- ERROR_LOOK_AT_PARAM_MISSING = 'You cannot just "look at". You gotta choose something to look at.'
22
- ERROR_TALK_PARAM_INVALID = 'Are you talking to yourself? That person is not here.'
23
- ERROR_TALK_PARAM_UNTALKABLE = 'That cannnot be conversed with.'
24
- ERROR_TALK_TO_PARAM_MISSING = 'You cannot just "talk to". You gotta choose someone to talk to.'
25
- ERROR_GO_PARAM_MISSING = 'Just wander aimlessly? A direction would be nice.'
26
- ERROR_GO_PARAM_INVALID = 'Something tells you that is not a way to go.'
27
- ERROR_DIRECTION_PARAM_INVALID = 'You cannot go to that place.'
28
- ERROR_ATTACK_PARAM_MISSING = 'You cannot just "attack". You gotta choose something to attack.'
29
- ERROR_ATTACK_PARAM_INVALID = 'That monster does not exist here or can\'t be attacked.'
30
- ERROR_BREAKTHRU_PARAM_MISSING = 'You cannot just "breakthru". You gotta specify a location name.'
31
- ERROR_BREAKTHRU_PARAM_INVALID = 'You cannot breakthru to that place.'
32
- ERROR_BREAKTHRU_INEXPERIENCED = 'You are not experienced enough to perform that feat.'
33
- ERROR_TAKE_PARAM_MISSING = 'You cannot just "take". You gotta choose something to take.'
34
- ERROR_USE_PARAM_MISSING = 'You cannot just "use". You gotta choose something to use.'
35
- ERROR_USE_PARAM_INVALID = 'You cannot use that, as it does not exist here or in your inventory.'
36
- ERROR_USE_PARAM_UNUSEABLE = 'That is not useable.'
37
- ERROR_DROP_PARAM_MISSING = 'You cannot just "drop". You gotta choose something to drop.'
38
- ERROR_EQUIP_PARAM_MISSING = 'You cannot just "equip". You gotta choose something to equip.'
39
- ERROR_UNEQUIP_PARAM_MISSING = 'You cannot just "unequip". You gotta choose something to unequip.'
40
- ERROR_CHANGE_PARAM_MISSING = 'You cannot just "change". You gotta choose something to change.'
41
- ERROR_CHANGE_PARAM_INVALID = 'You cannot change that...yet.'
42
- ERROR_LIST_PARAM_MISSING = 'You cannot just "list". You gotta choose something to list.'
43
- ERROR_LIST_PARAM_INVALID = 'You cannot list that...yet.'
44
- ERROR_DEBUG_STAT_PARAM_MISSING = 'You cannot just "change stats". You gotta choose a stat to change.'
45
- ERROR_DEBUG_STAT_PARAM_INVALID = 'You cannot change that stat...yet.'
46
- ERROR_DEBUG_STAT_INV_PARAM_INVALID = 'You cannot add that to your inventory...yet.'
47
- ERROR_DEBUG_GLOBAL_VAR_INVALID = 'That global variable does not exist.'
48
- ERROR_DEBUG_TELEPORT_PARAMS_MISSING = 'You cannot just "teleport". You gotta specify an x AND y coordinate, at least.'
49
- ERROR_DEBUG_TELEPORT_PARAMS_NEEDED = 'You cannot just "teleport" to an x coordinate without a y coordinate.'
50
- ERROR_DEBUG_TELEPORT_PARAMS_INVALID = 'You cannot teleport there...yet.'
51
-
52
- attr_accessor :world,
53
- :commands,
54
- :aliases,
55
- :extras,
56
- :cmd_descriptions,
57
- :devcommands,
58
- :devaliases,
59
- :devextras,
60
- :devcmd_descriptions
61
-
62
- def initialize(world)
63
- self.world = world
64
-
65
- self.devcommands = %w(god beast constants list vars map stat global teleport spawn levelbump restfight)
66
- self.devaliases = %w(gd bs cn ls vs m st gl tp sp lb rf)
67
- self.devextras = %w()
68
- self.devcmd_descriptions = [
69
- 'Toggle god mode (i.e. invincible)',
70
- 'Toggle beast mode (i.e. super strength)',
71
- 'List all GameAssets',
72
- 'List all instances of a specific entity type',
73
- 'List all the variables in the world',
74
- 'Show a map of the world',
75
- 'Change player stat',
76
- 'Change world global variable',
77
- 'Teleport to coordinates (5 0 0) or name (\'Home\')',
78
- 'Spawn random monster',
79
- 'Bump your character up *n* levels',
80
- 'Rest, but ensure battle for testing'
81
- ]
82
-
83
- self.commands = %w(character look rest take talk inventory use open drop equip unequip go north east south west attack breakthru change version checkupdate help quit quit!)
84
- self.aliases = %w(c l r t tk i u o d eq ue g n e s w a br ch v cu h q qq)
85
- self.extras = %w(exit exit! x xx fight f ? ?? ???)
86
- self.cmd_descriptions = [
87
- 'Display character information',
88
- 'Look around your current location',
89
- 'Take a load off and regain HP',
90
- 'Take item',
91
- 'Talk to person',
92
- 'Look in your inventory',
93
- 'Use item (in inventory or environment)',
94
- 'Open item (in inventory or environment)',
95
- 'Drop item',
96
- 'Equip item',
97
- 'Unequip item',
98
- 'Go in a direction',
99
- 'Go north (shortcut)',
100
- 'Go east (shortcut)',
101
- 'Go south (shortcut)',
102
- 'Go west (shortcut)',
103
- 'Attack a monster (also fight)',
104
- 'Teleport to a location (if you are experienced enough)',
105
- 'Change attribute',
106
- 'Display game version',
107
- 'Check for newer game releases',
108
- 'This help menu (also ?)',
109
- 'Quit w/ confirmation (also exit/x)',
110
- 'Quit w/o confirmation (also exit!/xx)'
111
- ]
112
- end
113
-
114
- def parse(input)
115
- case input
116
- # Ctrl-D or empty command
117
- when nil, ''
118
- return
119
- # real command
120
- else
121
- return ERROR_COMMAND_INVALID.colorize(:red) unless input_valid?(input)
122
- end
123
-
124
- tokens = input.split
125
- command = tokens.first.downcase
126
- param1 = tokens[1]
127
- param2 = tokens[2]
128
- param3 = tokens[3]
129
-
130
- # helpful
131
- player_cur_location = world.location_by_coords(world.player.cur_coords)
132
-
133
- # dev commands
134
- if GameOptions.data['debug_mode']
135
- case command
136
- when 'god', 'gd'
137
- GameOptions.data['god_mode'] = !GameOptions.data['god_mode']
138
- return "God mode set to #{GameOptions.data['god_mode']}"
139
- when 'beast', 'bs'
140
- GameOptions.data['beast_mode'] = !GameOptions.data['beast_mode']
141
- return "Beast mode set to #{GameOptions.data['beast_mode']}"
142
- when 'constants', 'cn'
143
- puts 'GameCreatures'.colorize(:yellow)
144
- puts GameCreatures.data
145
- STDIN.getc
146
- puts 'GameMonsters'.colorize(:yellow)
147
- puts GameMonsters.data
148
- STDIN.getc
149
- puts 'GamePeople'.colorize(:yellow)
150
- puts GamePeople.data
151
- STDIN.getc
152
- puts 'GameItems'.colorize(:yellow)
153
- puts GameItems.data
154
- STDIN.getc
155
- puts 'GameArmor'.colorize(:yellow)
156
- puts GameArmor.data
157
- STDIN.getc
158
- puts 'GameWeapons'.colorize(:yellow)
159
- puts GameWeapons.data
160
- when 'vars', 'vs'
161
- if param1
162
- world.print_vars(param1)
163
- else
164
- world.print_vars
165
- end
166
- when 'list', 'ls'
167
- if param1.nil?
168
- puts ERROR_LIST_PARAM_MISSING
169
- return DEBUG_LIST_PARAMS
170
- else
171
- return world.list(param1, param2)
172
- end
173
- when 'map', 'm'
174
- world.print_map(param1)
175
- when 'stat', 'st'
176
- if param1.nil?
177
- puts ERROR_DEBUG_STAT_PARAM_MISSING
178
- return DEBUG_STAT_PARAMS
179
- else
180
- case param1
181
- when 'hp_cur', 'hp'
182
- unless param2.nil?
183
- param2 = param2.to_i
184
- if param2.is_a? Numeric
185
- if param2 > 0
186
- world.player.hp_cur = param2
187
- end
188
- end
189
- end
190
- when 'atk_lo'
191
- unless param2.nil?
192
- param2 = param2.to_i
193
- if param2.is_a? Numeric
194
- if param2 >= 0
195
- world.player.atk_lo = param2
196
- end
197
- end
198
- end
199
- when 'atk_hi'
200
- unless param2.nil?
201
- param2 = param2.to_i
202
- if param2.is_a? Numeric
203
- if param2 >= 0
204
- world.player.atk_hi = param2
205
- end
206
- end
207
- end
208
- when 'strength', 'str', 'st'
209
- unless param2.nil?
210
- param2 = param2.to_i
211
- if param2.is_a? Numeric
212
- if param2 >= 0
213
- world.player.atk_lo = param2
214
- world.player.atk_hi = param2
215
- end
216
- end
217
- end
218
- when 'dexterity', 'dex'
219
- unless param2.nil?
220
- param2 = param2.to_i
221
- if param2.is_a? Numeric
222
- if param2 >= 0
223
- world.player.dexterity = param2
224
- end
225
- end
226
- end
227
- when 'defense', 'def'
228
- unless param2.nil?
229
- param2 = param2.to_i
230
- if param2.is_a? Numeric
231
- if param2 >= 0
232
- world.player.defense = param2
233
- end
234
- end
235
- end
236
- when 'rox', 'r', '$'
237
- unless param2.nil?
238
- param2 = param2.to_i
239
- if param2.is_a? Numeric
240
- if param2 >= 0
241
- world.player.rox = param2
242
- end
243
- end
244
- end
245
- when 'experience', 'xp'
246
- unless param2.nil?
247
- param2 = param2.to_i
248
- if param2.is_a? Numeric
249
- if param2 >= 0
250
- world.player.xp = param2
251
- end
252
- end
253
- end
254
- when 'inventory', 'inv'
255
- unless param2.nil?
256
- begin
257
- item_const_name = Gemwarrior.const_get(Formatting.upstyle(param2, no_space: true))
258
- item = item_const_name.new
259
- world.player.inventory.items.push(item)
260
- return "#{item.name.colorize(:yellow)} added to player inventory."
261
- rescue
262
- return ERROR_DEBUG_STAT_INV_PARAM_INVALID
263
- end
264
- end
265
- else
266
- return ERROR_DEBUG_STAT_PARAM_INVALID
267
- end
268
- end
269
- when 'global', 'gl'
270
- if param1.nil?
271
- return world.instance_variables.join(', ')
272
- elsif world.instance_variable_get("@#{param1}").nil?
273
- return ERROR_DEBUG_GLOBAL_VAR_INVALID
274
- elsif param2.nil?
275
- return world.instance_variable_get("@#{param1}").to_s
276
- else
277
- val = false
278
- val = param2.eql?('true') ? true : val
279
-
280
- world.instance_variable_set("@#{param1}", val)
281
- return "Instance variable #{param1} has been set to #{val}."
282
- end
283
- when 'spawn', 'sp'
284
- player_cur_location = world.location_by_coords(world.player.cur_coords)
285
- player_cur_location.populate_monsters(GameMonsters.data, true, param1)
286
- return world.describe(player_cur_location)
287
- when 'teleport', 'tp'
288
- if param1.nil?
289
- return ERROR_DEBUG_TELEPORT_PARAMS_MISSING
290
- else
291
- if (param1.to_i.to_s == param1)
292
- # we got at least an x coordinate
293
- if (param2.to_i.to_s == param2)
294
- # we got a y coordinate, too
295
- x_coord = param1.to_i
296
- y_coord = param2.to_i
297
- # grab the z coordinate, if present, otherwise default to current level
298
- z_coord = param3.to_i.to_s == param3 ? param3.to_i : world.player.cur_coords[:z]
299
-
300
- # check to make sure new location exists
301
- if world.location_by_coords(x: x_coord, y: y_coord, z: z_coord)
302
- world.player.cur_coords = { x: x_coord, y: y_coord, z: z_coord }
303
- else
304
- return ERROR_DEBUG_TELEPORT_PARAMS_INVALID
305
- end
306
- else
307
- # we only got an x coordinate
308
- return ERROR_DEBUG_TELEPORT_PARAMS_NEEDED
309
- end
310
- else
311
- # we got a place name instead, potentially
312
- place_to_match = tokens[1..tokens.length].join(' ').downcase
313
- locations = []
314
- world.locations.each do |l|
315
- locations << l.name.downcase
316
- end
317
- if locations.include?(place_to_match)
318
- world.player.cur_coords = world.location_coords_by_name(place_to_match)
319
- else
320
- return ERROR_DEBUG_TELEPORT_PARAMS_INVALID
321
- end
322
- end
323
-
324
- # stats
325
- world.player.movements_made += 1
326
-
327
- Animation.run(phrase: '** TELEPORT! **', speed: :insane)
328
- player_cur_location = world.location_by_coords(world.player.cur_coords)
329
- return world.describe(player_cur_location)
330
- end
331
- when 'levelbump', 'lb'
332
- new_level = param1.nil? ? 1 : param1.to_i
333
- world.player.update_stats(reason: :level_bump, value: new_level)
334
- when 'restfight', 'rf'
335
- result = world.player.rest(world, 0, true)
336
-
337
- if result.eql?('death')
338
- player_death_resurrection
339
- end
340
- end
341
- end
342
-
343
- # normal commands
344
- case command
345
- when 'character', 'c'
346
- # bypass puts so it prints out with newlines properly
347
- print world.player.check_self
348
- when 'inventory', 'i'
349
- if param1
350
- world.player.inventory.describe_item(param1)
351
- else
352
- world.player.list_inventory
353
- end
354
- when 'look', 'l'
355
- if param1
356
- # convert 'look at' to 'look'
357
- if param1.eql?('at')
358
- if param2
359
- param1 = param2
360
- else
361
- return ERROR_LOOK_AT_PARAM_MISSING
362
- end
363
- end
364
- world.describe_entity(player_cur_location, param1)
365
- else
366
- world.describe(player_cur_location)
367
- end
368
- when 'rest', 'r'
369
- tent_uses = 0
370
- player_inventory = world.player.inventory
371
-
372
- if player_inventory.contains_item?('tent')
373
- player_inventory.items.each do |i|
374
- if i.name.eql?('tent')
375
- if i.number_of_uses > 0
376
- result = i.use(world)
377
- tent_uses = i.number_of_uses
378
- i.number_of_uses -= 1
379
-
380
- puts ">> tent can be used when resting #{i.number_of_uses} more time(s)."
381
- end
382
- end
383
- end
384
- elsif player_cur_location.contains_item?('tent')
385
- player_cur_location.items.each do |i|
386
- if i.name.eql?('tent')
387
- if i.number_of_uses > 0
388
- result = i.use(world)
389
- tent_uses = i.number_of_uses
390
- i.number_of_uses -= 1
391
-
392
- puts ">> tent can be used when resting #{i.number_of_uses} more time(s)."
393
- end
394
- end
395
- end
396
- end
397
-
398
- result = world.player.rest(world, tent_uses)
399
-
400
- if result.eql?('death')
401
- player_death_resurrection
402
- else
403
- result
404
- end
405
- when 'take', 't'
406
- if param1.nil?
407
- ERROR_TAKE_PARAM_MISSING
408
- else
409
- world.player.inventory.add_item(param1, player_cur_location, world.player)
410
- end
411
- when 'talk', 'tk'
412
- if param1.nil?
413
- return ERROR_TALK_TO_PARAM_MISSING
414
- elsif param1.eql?('to')
415
- if param2
416
- param1 = param2
417
- else
418
- return ERROR_TALK_TO_PARAM_MISSING
419
- end
420
- end
421
-
422
- talkable_name = param1
423
-
424
- player_inventory = world.player.inventory
425
-
426
- if player_inventory.contains_item?(talkable_name)
427
- player_inventory.items.each do |person|
428
- if person.name.eql?(talkable_name)
429
- if person.talkable
430
- return self.parse("use #{talkable_name}")
431
- else
432
- return ERROR_TALK_PARAM_UNTALKABLE
433
- end
434
- end
435
- end
436
- elsif player_cur_location.contains_item?(talkable_name)
437
- player_cur_location.items.each do |person|
438
- if person.name.eql?(talkable_name)
439
- if person.talkable
440
- return self.parse("use #{talkable_name}")
441
- else
442
- return ERROR_TALK_PARAM_UNTALKABLE
443
- end
444
- end
445
- end
446
- elsif player_cur_location.has_monster?(talkable_name)
447
- player_cur_location.monsters_abounding.each do |monster|
448
- if monster.name.eql?(talkable_name)
449
- if monster.talkable
450
- return self.parse("use #{talkable_name}")
451
- else
452
- return ERROR_TALK_PARAM_UNTALKABLE
453
- end
454
- end
455
- end
456
- elsif player_cur_location.has_boss?(talkable_name)
457
- player_cur_location.bosses_abounding.each do |boss|
458
- if boss.name.eql?(talkable_name)
459
- if boss.talkable
460
- return self.parse("use #{talkable_name}")
461
- else
462
- return ERROR_TALK_PARAM_UNTALKABLE
463
- end
464
- end
465
- end
466
- end
467
- when 'use', 'u', 'open', 'o'
468
- if param1.nil?
469
- ERROR_USE_PARAM_MISSING
470
- else
471
- item_name = param1
472
- result = nil
473
-
474
- player_inventory = world.player.inventory
475
-
476
- if player_inventory.contains_item?(item_name)
477
- player_inventory.items.each do |i|
478
- if i.name.eql?(item_name)
479
- if i.useable
480
- if !i.number_of_uses.nil?
481
- if i.number_of_uses > 0
482
- result = i.use(world)
483
- i.number_of_uses -= 1
484
- puts ">> #{i.name} can be used #{i.number_of_uses} more time(s)."
485
- break
486
- else
487
- return ">> #{i.name} cannot be used anymore."
488
- end
489
- elsif i.consumable
490
- result = i.use(world)
491
- world.player.inventory.remove_item(i.name)
492
- break
493
- else
494
- result = i.use(world)
495
- break
496
- end
497
- else
498
- return ERROR_USE_PARAM_UNUSEABLE
499
- end
500
- end
501
- end
502
- elsif player_cur_location.contains_item?(item_name)
503
- player_cur_location.items.each do |i|
504
- if i.name.eql?(item_name)
505
- if i.useable
506
- if !i.number_of_uses.nil?
507
- if i.number_of_uses > 0
508
- result = i.use(world)
509
- i.number_of_uses -= 1
510
- puts ">> #{i.name} can be used #{i.number_of_uses} more time(s)."
511
- break
512
- else
513
- return ">> #{i.name} cannot be used anymore."
514
- end
515
- elsif i.consumable
516
- result = i.use(world)
517
- location.remove_item(i.name)
518
- break
519
- else
520
- result = i.use(world)
521
- break
522
- end
523
- else
524
- return ERROR_USE_PARAM_UNUSEABLE
525
- end
526
- end
527
- end
528
- elsif player_cur_location.has_monster?(item_name)
529
- player_cur_location.monsters_abounding.each do |i|
530
- if i.name.eql?(item_name)
531
- return i.use(world)
532
- end
533
- end
534
- elsif player_cur_location.has_boss?(item_name)
535
- player_cur_location.bosses_abounding.each do |i|
536
- if i.name.eql?(item_name)
537
- return i.use(world)
538
- end
539
- end
540
- end
541
-
542
- if result.nil?
543
- ERROR_USE_PARAM_INVALID
544
- else
545
- case result[:type]
546
- when 'move'
547
- world.player.cur_coords = world.location_coords_by_name(result[:data])
548
- player_cur_location = world.location_by_coords(world.player.cur_coords)
549
- world.describe(player_cur_location)
550
- when 'move_dangerous'
551
- dmg = rand(0..2)
552
- puts ">> You lose #{dmg} hit point(s)." if dmg > 0
553
- world.player.take_damage(dmg)
554
-
555
- world.player.cur_coords = world.location_coords_by_name(result[:data])
556
- player_cur_location = world.location_by_coords(world.player.cur_coords)
557
- world.describe(player_cur_location)
558
- when 'dmg'
559
- result = world.player.take_damage(result[:data])
560
-
561
- if result.eql?('death')
562
- player_death_resurrection
563
- end
564
- when 'rest', 'health'
565
- world.player.heal_damage(result[:data])
566
- return
567
- when 'xp'
568
- world.player.update_stats(reason: :xp, value: result[:data])
569
- return
570
- when 'tent'
571
- world.player.rest(world, result[:data])
572
- when 'action'
573
- case result[:data]
574
- when 'map'
575
- world.print_map(world.player.cur_coords[:z])
576
- end
577
- when 'arena'
578
- arena = Arena.new(world: world, player: world.player)
579
- result = arena.start
580
-
581
- if result.eql?('death')
582
- player_death_resurrection
583
- end
584
- when 'item'
585
- player_cur_location.add_item(result[:data])
586
- return
587
- when 'purchase'
588
- result[:data].each do |i|
589
- world.player.inventory.items.push(i)
590
- end
591
- return
592
- else
593
- return
594
- end
595
- end
596
- end
597
- when 'drop', 'd'
598
- if param1.nil?
599
- ERROR_DROP_PARAM_MISSING
600
- else
601
- world.player.inventory.drop_item(param1, player_cur_location)
602
- end
603
- when 'equip', 'eq'
604
- if param1.nil?
605
- ERROR_EQUIP_PARAM_MISSING
606
- else
607
- world.player.inventory.equip_item(param1)
608
- end
609
- when 'unequip', 'ue'
610
- if param1.nil?
611
- ERROR_UNEQUIP_PARAM_MISSING
612
- else
613
- world.player.inventory.unequip_item(param1)
614
- end
615
- when 'go', 'g'
616
- if param1.nil?
617
- puts ERROR_GO_PARAM_MISSING
618
- GO_PARAMS
619
- else
620
- direction = param1
621
- try_to_move_player(direction)
622
- end
623
- when 'n'
624
- if param1
625
- ERROR_DIRECTION_PARAM_INVALID
626
- else
627
- try_to_move_player('north')
628
- end
629
- when 'e'
630
- if param1
631
- ERROR_DIRECTION_PARAM_INVALID
632
- else
633
- try_to_move_player('east')
634
- end
635
- when 's'
636
- if param1
637
- ERROR_DIRECTION_PARAM_INVALID
638
- else
639
- try_to_move_player('south')
640
- end
641
- when 'w'
642
- if param1
643
- ERROR_DIRECTION_PARAM_INVALID
644
- else
645
- try_to_move_player('west')
646
- end
647
- when 'attack', 'a', 'fight', 'f'
648
- if param1.nil?
649
- if GameOptions.data['fight_completion']
650
- if player_cur_location.has_any_monsters?
651
- monster_param = player_cur_location.monsters_abounding[0].name
652
- self.parse("attack #{monster_param}")
653
- else
654
- ERROR_ATTACK_PARAM_INVALID
655
- end
656
- else
657
- ERROR_ATTACK_PARAM_MISSING
658
- end
659
- else
660
- monster_name = param1
661
- if world.has_monster_to_attack?(monster_name)
662
- monster = player_cur_location.monster_by_name(monster_name)
663
- result = world.player.attack(world, monster, param2)
664
-
665
- if result.eql?('death')
666
- return player_death_resurrection
667
- elsif result.eql?('exit')
668
- return 'exit'
669
- end
670
-
671
- unless result.nil?
672
- case result[:type]
673
- when 'message'
674
- result[:data]
675
- when 'move'
676
- world.player.cur_coords = world.location_coords_by_name(result[:data])
677
- player_cur_location = world.location_by_coords(world.player.cur_coords)
678
- world.describe(player_cur_location)
679
- end
680
- end
681
- else
682
- ERROR_ATTACK_PARAM_INVALID
683
- end
684
- end
685
- when 'breakthru', 'br'
686
- if world.player.special_abilities.include?(:breakthru)
687
- if param1.nil?
688
- return ERROR_BREAKTHRU_PARAM_MISSING
689
- else
690
- place_to_match = tokens[1..tokens.length].join(' ').downcase
691
- locations = []
692
- world.locations.each do |l|
693
- locations << l.name.downcase
694
- end
695
- if locations.include?(place_to_match)
696
- world.player.cur_coords = world.location_coords_by_name(place_to_match)
697
- else
698
- return ERROR_BREAKTHRU_PARAM_INVALID
699
- end
700
- end
701
-
702
- # stats
703
- world.player.movements_made += 1
704
-
705
- Animation.run(phrase: '** BREAK THROUGH! **')
706
- player_cur_location = world.location_by_coords(world.player.cur_coords)
707
- return world.describe(player_cur_location)
708
- else
709
- ERROR_BREAKTHRU_INEXPERIENCED
710
- end
711
- when 'change', 'ch'
712
- if param1.nil?
713
- puts ERROR_CHANGE_PARAM_MISSING
714
- CHANGE_PARAMS
715
- else
716
- case param1
717
- when 'name'
718
- world.player.modify_name
719
- else
720
- ERROR_CHANGE_PARAM_INVALID
721
- end
722
- end
723
- when 'help', 'h', '?', '??', '???'
724
- list_commands
725
- when 'version', 'v'
726
- Gemwarrior::VERSION
727
- when 'checkupdate', 'cu'
728
- 'checkupdate'
729
- when 'quit', 'exit', 'q', 'x'
730
- print 'You sure you want to quit? (y/n) '
731
- answer = gets.chomp.downcase
732
-
733
- case answer
734
- when 'y', 'yes'
735
- puts QUIT_MESSAGE.colorize(:yellow)
736
- return 'exit'
737
- else
738
- puts RESUME_MESSAGE.colorize(:green)
739
- end
740
- when 'quit!', 'exit!', 'qq', 'xx'
741
- puts QUIT_MESSAGE.colorize(:yellow)
742
- return 'exit'
743
- else
744
- return
745
- end
746
- end
747
-
748
- private
749
-
750
- def try_to_move_player(direction)
751
- if world.can_move?(direction)
752
- world.player.go(world, direction)
753
- player_cur_location = world.location_by_coords(world.player.cur_coords)
754
- player_cur_location.checked_for_monsters = false
755
-
756
- if player_cur_location.name.include?('pain_quarry')
757
- if player_cur_location.has_boss?('garynetty')
758
- roll = rand(0..100) + world.player.dexterity
759
- roll_display = roll < 25 ? "#{roll}".colorize(:red) : "#{roll}".colorize(:green)
760
- puts "[Pain Quarry Garynetty Roll: #{roll_display}]" if GameOptions.data['debug_mode']
761
- if roll < 25
762
- self.parse("attack garynetty is_ambush")
763
- else
764
- puts 'You nearly got attacked by a vicious Garynetty! Be careful, your next move might not be as lucky.'.colorize(:yellow)
765
- end
766
- end
767
- end
768
-
769
- world.describe(player_cur_location)
770
- else
771
- return ERROR_GO_PARAM_INVALID.colorize(:red)
772
- end
773
- end
774
-
775
- def player_death_resurrection
776
- Audio.play_synth(:player_resurrection)
777
-
778
- puts 'Somehow, though, your adventure does not end here!'.colorize(:yellow)
779
- puts 'Instead, you are whisked back home via some magical force.'.colorize(:yellow)
780
- puts 'A bit worse for the weary and somewhat poorer, but you are ALIVE!'.colorize(:yellow)
781
- puts
782
-
783
- world.player.hp_cur = 1
784
- world.player.rox -= (world.player.rox * 0.1).to_i
785
- if world.player.rox < 0
786
- world.player.rox = 0
787
- end
788
- world.player.cur_coords = world.location_coords_by_name('Home')
789
- player_cur_location = world.location_by_coords(world.player.cur_coords)
790
- world.describe(player_cur_location)
791
- world.player.deaths += 1
792
- return
793
- end
794
-
795
- def list_commands
796
- i = 0
797
- Hr.print('=')
798
- puts ' COMMAND | ALIAS | DESCRIPTION '
799
- Hr.print('=')
800
- commands.each do |cmd|
801
- puts " #{cmd.ljust(11)} | #{aliases[i].ljust(5)} | #{cmd_descriptions[i]}"
802
- i += 1
803
- end
804
- Hr.print('=')
805
-
806
- if GameOptions.data['debug_mode']
807
- puts ' DEBUG COMMANDS'
808
- Hr.print('=')
809
- i = 0
810
- devcommands.each do |cmd|
811
- puts " #{cmd.ljust(11)} | #{devaliases[i].ljust(5)} | #{devcmd_descriptions[i]}"
812
- i += 1
813
- end
814
- Hr.print('=')
815
- end
816
- end
817
-
818
- def input_valid?(input)
819
- tokens = input.split
820
- command = tokens[0]
821
- commands_and_aliases = commands | aliases | extras
822
-
823
- if GameOptions.data['debug_mode']
824
- commands_and_aliases = commands_and_aliases | devcommands | devaliases | devextras
825
- end
826
-
827
- if commands_and_aliases.include?(command.downcase)
828
- if tokens.size.between?(1, 4)
829
- return true
830
- end
831
- elsif tokens.empty?
832
- return true
833
- end
834
- end
835
- end
836
- end
1
+ # lib/gemwarrior/evaluator.rb
2
+ # Evaluates prompt input
3
+
4
+ require_relative 'arena'
5
+ require_relative 'game_assets'
6
+ require_relative 'game_options'
7
+
8
+ module Gemwarrior
9
+ class Evaluator
10
+ # CONSTANTS
11
+ PROGRAM_NAME = 'Gem Warrior'
12
+ QUIT_MESSAGE = 'Thanks for playing the game. Until next time...'
13
+ RESUME_MESSAGE = 'Back to adventuring!'
14
+
15
+ GO_PARAMS = 'Options: north, east, south, west'
16
+ CHANGE_PARAMS = 'Options: name'
17
+ DEBUG_LIST_PARAMS = 'Options: players, creatures, items, locations, monsters, weapons, armor'
18
+ DEBUG_STAT_PARAMS = 'Options: hp_cur, atk_lo, atk_hi, experience, rox, strength, dexterity, defense, inventory'
19
+
20
+ ERROR_COMMAND_INVALID = 'That is not something the game yet understands.'
21
+ ERROR_LOOK_AT_PARAM_MISSING = 'You cannot just "look at". You gotta choose something to look at.'
22
+ ERROR_TALK_PARAM_INVALID = 'Are you talking to yourself? That person is not here.'
23
+ ERROR_TALK_PARAM_UNTALKABLE = 'That cannnot be conversed with.'
24
+ ERROR_TALK_TO_PARAM_MISSING = 'You cannot just "talk to". You gotta choose someone to talk to.'
25
+ ERROR_GO_PARAM_MISSING = 'Just wander aimlessly? A direction would be nice.'
26
+ ERROR_GO_PARAM_INVALID = 'Something tells you that is not a way to go.'
27
+ ERROR_DIRECTION_PARAM_INVALID = 'You cannot go to that place.'
28
+ ERROR_ATTACK_PARAM_MISSING = 'You cannot just "attack". You gotta choose something to attack.'
29
+ ERROR_ATTACK_PARAM_INVALID = 'That monster does not exist here or can\'t be attacked.'
30
+ ERROR_BREAKTHRU_PARAM_MISSING = 'You cannot just "breakthru". You gotta specify a location name.'
31
+ ERROR_BREAKTHRU_PARAM_INVALID = 'You cannot breakthru to that place.'
32
+ ERROR_BREAKTHRU_INEXPERIENCED = 'You are not experienced enough to perform that feat.'
33
+ ERROR_TAKE_PARAM_MISSING = 'You cannot just "take". You gotta choose something to take.'
34
+ ERROR_USE_PARAM_MISSING = 'You cannot just "use". You gotta choose something to use.'
35
+ ERROR_USE_PARAM_INVALID = 'You cannot use that, as it does not exist here or in your inventory.'
36
+ ERROR_USE_PARAM_UNUSEABLE = 'That is not useable.'
37
+ ERROR_DROP_PARAM_MISSING = 'You cannot just "drop". You gotta choose something to drop.'
38
+ ERROR_EQUIP_PARAM_MISSING = 'You cannot just "equip". You gotta choose something to equip.'
39
+ ERROR_UNEQUIP_PARAM_MISSING = 'You cannot just "unequip". You gotta choose something to unequip.'
40
+ ERROR_CHANGE_PARAM_MISSING = 'You cannot just "change". You gotta choose something to change.'
41
+ ERROR_CHANGE_PARAM_INVALID = 'You cannot change that...yet.'
42
+ ERROR_LIST_PARAM_MISSING = 'You cannot just "list". You gotta choose something to list.'
43
+ ERROR_LIST_PARAM_INVALID = 'You cannot list that...yet.'
44
+ ERROR_DEBUG_STAT_PARAM_MISSING = 'You cannot just "change stats". You gotta choose a stat to change.'
45
+ ERROR_DEBUG_STAT_PARAM_INVALID = 'You cannot change that stat...yet.'
46
+ ERROR_DEBUG_STAT_INV_PARAM_INVALID = 'You cannot add that to your inventory...yet.'
47
+ ERROR_DEBUG_GLOBAL_VAR_INVALID = 'That global variable does not exist.'
48
+ ERROR_DEBUG_TELEPORT_PARAMS_MISSING = 'You cannot just "teleport". You gotta specify an x AND y coordinate, at least.'
49
+ ERROR_DEBUG_TELEPORT_PARAMS_NEEDED = 'You cannot just "teleport" to an x coordinate without a y coordinate.'
50
+ ERROR_DEBUG_TELEPORT_PARAMS_INVALID = 'You cannot teleport there...yet.'
51
+
52
+ attr_accessor :world,
53
+ :commands,
54
+ :aliases,
55
+ :extras,
56
+ :cmd_descriptions,
57
+ :devcommands,
58
+ :devaliases,
59
+ :devextras,
60
+ :devcmd_descriptions
61
+
62
+ def initialize(world)
63
+ self.world = world
64
+
65
+ self.devcommands = %w(god beast constants list vars map stat global teleport spawn levelbump restfight)
66
+ self.devaliases = %w(gd bs cn ls vs m st gl tp sp lb rf)
67
+ self.devextras = %w()
68
+ self.devcmd_descriptions = [
69
+ 'Toggle god mode (i.e. invincible)',
70
+ 'Toggle beast mode (i.e. super strength)',
71
+ 'List all GameAssets',
72
+ 'List all instances of a specific entity type',
73
+ 'List all the variables in the world',
74
+ 'Show a map of the world',
75
+ 'Change player stat',
76
+ 'Change world global variable',
77
+ 'Teleport to coordinates (5 0 0) or name (\'Home\')',
78
+ 'Spawn random monster',
79
+ 'Bump your character up *n* levels',
80
+ 'Rest, but ensure battle for testing'
81
+ ]
82
+
83
+ self.commands = %w(character look rest take talk inventory use open drop equip unequip go north east south west attack breakthru change version checkupdate help quit quit!)
84
+ self.aliases = %w(c l r t tk i u o d eq ue g n e s w a br ch v cu h q qq)
85
+ self.extras = %w(exit exit! x xx fight f ? ?? ???)
86
+ self.cmd_descriptions = [
87
+ 'Display character information',
88
+ 'Look around your current location',
89
+ 'Take a load off and regain HP',
90
+ 'Take item',
91
+ 'Talk to person',
92
+ 'Look in your inventory',
93
+ 'Use item (in inventory or environment)',
94
+ 'Open item (in inventory or environment)',
95
+ 'Drop item',
96
+ 'Equip item',
97
+ 'Unequip item',
98
+ 'Go in a direction',
99
+ 'Go north (shortcut)',
100
+ 'Go east (shortcut)',
101
+ 'Go south (shortcut)',
102
+ 'Go west (shortcut)',
103
+ 'Attack a monster (also fight)',
104
+ 'Teleport to a location (if you are experienced enough)',
105
+ 'Change attribute',
106
+ 'Display game version',
107
+ 'Check for newer game releases',
108
+ 'This help menu (also ?)',
109
+ 'Quit w/ confirmation (also exit/x)',
110
+ 'Quit w/o confirmation (also exit!/xx)'
111
+ ]
112
+ end
113
+
114
+ def parse(input)
115
+ case input
116
+ # Ctrl-D or empty command
117
+ when nil, ''
118
+ return
119
+ # real command
120
+ else
121
+ return ERROR_COMMAND_INVALID.colorize(:red) unless input_valid?(input)
122
+ end
123
+
124
+ tokens = input.split
125
+ command = tokens.first.downcase
126
+ param1 = tokens[1]
127
+ param2 = tokens[2]
128
+ param3 = tokens[3]
129
+
130
+ # helpful
131
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
132
+
133
+ # dev commands
134
+ if GameOptions.data['debug_mode']
135
+ case command
136
+ when 'god', 'gd'
137
+ GameOptions.data['god_mode'] = !GameOptions.data['god_mode']
138
+ return "God mode set to #{GameOptions.data['god_mode']}"
139
+ when 'beast', 'bs'
140
+ GameOptions.data['beast_mode'] = !GameOptions.data['beast_mode']
141
+ return "Beast mode set to #{GameOptions.data['beast_mode']}"
142
+ when 'constants', 'cn'
143
+ puts 'GameCreatures'.colorize(:yellow)
144
+ puts GameCreatures.data
145
+ STDIN.getc
146
+ puts 'GameMonsters'.colorize(:yellow)
147
+ puts GameMonsters.data
148
+ STDIN.getc
149
+ puts 'GamePeople'.colorize(:yellow)
150
+ puts GamePeople.data
151
+ STDIN.getc
152
+ puts 'GameItems'.colorize(:yellow)
153
+ puts GameItems.data
154
+ STDIN.getc
155
+ puts 'GameArmor'.colorize(:yellow)
156
+ puts GameArmor.data
157
+ STDIN.getc
158
+ puts 'GameWeapons'.colorize(:yellow)
159
+ puts GameWeapons.data
160
+ when 'vars', 'vs'
161
+ if param1
162
+ world.print_vars(param1)
163
+ else
164
+ world.print_vars
165
+ end
166
+ when 'list', 'ls'
167
+ if param1.nil?
168
+ puts ERROR_LIST_PARAM_MISSING
169
+ return DEBUG_LIST_PARAMS
170
+ else
171
+ return world.list(param1, param2)
172
+ end
173
+ when 'map', 'm'
174
+ world.print_map(param1)
175
+ when 'stat', 'st'
176
+ if param1.nil?
177
+ puts ERROR_DEBUG_STAT_PARAM_MISSING
178
+ return DEBUG_STAT_PARAMS
179
+ else
180
+ case param1
181
+ when 'hp_cur', 'hp'
182
+ unless param2.nil?
183
+ param2 = param2.to_i
184
+ if param2.is_a? Numeric
185
+ if param2 > 0
186
+ world.player.hp_cur = param2
187
+ end
188
+ end
189
+ end
190
+ when 'atk_lo'
191
+ unless param2.nil?
192
+ param2 = param2.to_i
193
+ if param2.is_a? Numeric
194
+ if param2 >= 0
195
+ world.player.atk_lo = param2
196
+ end
197
+ end
198
+ end
199
+ when 'atk_hi'
200
+ unless param2.nil?
201
+ param2 = param2.to_i
202
+ if param2.is_a? Numeric
203
+ if param2 >= 0
204
+ world.player.atk_hi = param2
205
+ end
206
+ end
207
+ end
208
+ when 'strength', 'str', 'st'
209
+ unless param2.nil?
210
+ param2 = param2.to_i
211
+ if param2.is_a? Numeric
212
+ if param2 >= 0
213
+ world.player.atk_lo = param2
214
+ world.player.atk_hi = param2
215
+ end
216
+ end
217
+ end
218
+ when 'dexterity', 'dex'
219
+ unless param2.nil?
220
+ param2 = param2.to_i
221
+ if param2.is_a? Numeric
222
+ if param2 >= 0
223
+ world.player.dexterity = param2
224
+ end
225
+ end
226
+ end
227
+ when 'defense', 'def'
228
+ unless param2.nil?
229
+ param2 = param2.to_i
230
+ if param2.is_a? Numeric
231
+ if param2 >= 0
232
+ world.player.defense = param2
233
+ end
234
+ end
235
+ end
236
+ when 'rox', 'r', '$'
237
+ unless param2.nil?
238
+ param2 = param2.to_i
239
+ if param2.is_a? Numeric
240
+ if param2 >= 0
241
+ world.player.rox = param2
242
+ end
243
+ end
244
+ end
245
+ when 'experience', 'xp'
246
+ unless param2.nil?
247
+ param2 = param2.to_i
248
+ if param2.is_a? Numeric
249
+ if param2 >= 0
250
+ world.player.xp = param2
251
+ end
252
+ end
253
+ end
254
+ when 'inventory', 'inv'
255
+ unless param2.nil?
256
+ begin
257
+ item_const_name = Gemwarrior.const_get(Formatting.upstyle(param2, no_space: true))
258
+ item = item_const_name.new
259
+ world.player.inventory.items.push(item)
260
+ return "#{item.name.colorize(:yellow)} added to player inventory."
261
+ rescue
262
+ return ERROR_DEBUG_STAT_INV_PARAM_INVALID
263
+ end
264
+ end
265
+ else
266
+ return ERROR_DEBUG_STAT_PARAM_INVALID
267
+ end
268
+ end
269
+ when 'global', 'gl'
270
+ if param1.nil?
271
+ return world.instance_variables.join(', ')
272
+ elsif world.instance_variable_get("@#{param1}").nil?
273
+ return ERROR_DEBUG_GLOBAL_VAR_INVALID
274
+ elsif param2.nil?
275
+ return world.instance_variable_get("@#{param1}").to_s
276
+ else
277
+ val = false
278
+ val = param2.eql?('true') ? true : val
279
+
280
+ world.instance_variable_set("@#{param1}", val)
281
+ return "Instance variable #{param1} has been set to #{val}."
282
+ end
283
+ when 'spawn', 'sp'
284
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
285
+ player_cur_location.populate_monsters(GameMonsters.data, true, param1)
286
+ return world.describe(player_cur_location)
287
+ when 'teleport', 'tp'
288
+ if param1.nil?
289
+ return ERROR_DEBUG_TELEPORT_PARAMS_MISSING
290
+ else
291
+ if (param1.to_i.to_s == param1)
292
+ # we got at least an x coordinate
293
+ if (param2.to_i.to_s == param2)
294
+ # we got a y coordinate, too
295
+ x_coord = param1.to_i
296
+ y_coord = param2.to_i
297
+ # grab the z coordinate, if present, otherwise default to current level
298
+ z_coord = param3.to_i.to_s == param3 ? param3.to_i : world.player.cur_coords[:z]
299
+
300
+ # check to make sure new location exists
301
+ if world.location_by_coords(x: x_coord, y: y_coord, z: z_coord)
302
+ world.player.cur_coords = { x: x_coord, y: y_coord, z: z_coord }
303
+ else
304
+ return ERROR_DEBUG_TELEPORT_PARAMS_INVALID
305
+ end
306
+ else
307
+ # we only got an x coordinate
308
+ return ERROR_DEBUG_TELEPORT_PARAMS_NEEDED
309
+ end
310
+ else
311
+ # we got a place name instead, potentially
312
+ place_to_match = tokens[1..tokens.length].join(' ').downcase
313
+ locations = []
314
+ world.locations.each do |l|
315
+ locations << l.name.downcase
316
+ end
317
+ if locations.include?(place_to_match)
318
+ world.player.cur_coords = world.location_coords_by_name(place_to_match)
319
+ else
320
+ return ERROR_DEBUG_TELEPORT_PARAMS_INVALID
321
+ end
322
+ end
323
+
324
+ # stats
325
+ world.player.movements_made += 1
326
+
327
+ Animation.run(phrase: '** TELEPORT! **', speed: :insane)
328
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
329
+ return world.describe(player_cur_location)
330
+ end
331
+ when 'levelbump', 'lb'
332
+ new_level = param1.nil? ? 1 : param1.to_i
333
+ world.player.update_stats(reason: :level_bump, value: new_level)
334
+ when 'restfight', 'rf'
335
+ result = world.player.rest(world, 0, true)
336
+
337
+ if result.eql?('death')
338
+ player_death_resurrection
339
+ end
340
+ end
341
+ end
342
+
343
+ # normal commands
344
+ case command
345
+ when 'character', 'c'
346
+ # bypass puts so it prints out with newlines properly
347
+ print world.player.check_self
348
+ when 'inventory', 'i'
349
+ if param1
350
+ world.player.inventory.describe_item(param1)
351
+ else
352
+ world.player.list_inventory
353
+ end
354
+ when 'look', 'l'
355
+ if param1
356
+ # convert 'look at' to 'look'
357
+ if param1.eql?('at')
358
+ if param2
359
+ param1 = param2
360
+ else
361
+ return ERROR_LOOK_AT_PARAM_MISSING
362
+ end
363
+ end
364
+ world.describe_entity(player_cur_location, param1)
365
+ else
366
+ world.describe(player_cur_location)
367
+ end
368
+ when 'rest', 'r'
369
+ tent_uses = 0
370
+ player_inventory = world.player.inventory
371
+
372
+ if player_inventory.contains_item?('tent')
373
+ player_inventory.items.each do |i|
374
+ if i.name.eql?('tent')
375
+ if i.number_of_uses > 0
376
+ result = i.use(world)
377
+ tent_uses = i.number_of_uses
378
+ i.number_of_uses -= 1
379
+
380
+ puts ">> tent can be used when resting #{i.number_of_uses} more time(s)."
381
+ end
382
+ end
383
+ end
384
+ elsif player_cur_location.contains_item?('tent')
385
+ player_cur_location.items.each do |i|
386
+ if i.name.eql?('tent')
387
+ if i.number_of_uses > 0
388
+ result = i.use(world)
389
+ tent_uses = i.number_of_uses
390
+ i.number_of_uses -= 1
391
+
392
+ puts ">> tent can be used when resting #{i.number_of_uses} more time(s)."
393
+ end
394
+ end
395
+ end
396
+ end
397
+
398
+ result = world.player.rest(world, tent_uses)
399
+
400
+ if result.eql?('death')
401
+ player_death_resurrection
402
+ else
403
+ result
404
+ end
405
+ when 'take', 't'
406
+ if param1.nil?
407
+ ERROR_TAKE_PARAM_MISSING
408
+ else
409
+ world.player.inventory.add_item(param1, player_cur_location, world.player)
410
+ end
411
+ when 'talk', 'tk'
412
+ if param1.nil?
413
+ return ERROR_TALK_TO_PARAM_MISSING
414
+ elsif param1.eql?('to')
415
+ if param2
416
+ param1 = param2
417
+ else
418
+ return ERROR_TALK_TO_PARAM_MISSING
419
+ end
420
+ end
421
+
422
+ talkable_name = param1
423
+
424
+ player_inventory = world.player.inventory
425
+
426
+ if player_inventory.contains_item?(talkable_name)
427
+ player_inventory.items.each do |person|
428
+ if person.name.eql?(talkable_name)
429
+ if person.talkable
430
+ return self.parse("use #{talkable_name}")
431
+ else
432
+ return ERROR_TALK_PARAM_UNTALKABLE
433
+ end
434
+ end
435
+ end
436
+ elsif player_cur_location.contains_item?(talkable_name)
437
+ player_cur_location.items.each do |person|
438
+ if person.name.eql?(talkable_name)
439
+ if person.talkable
440
+ return self.parse("use #{talkable_name}")
441
+ else
442
+ return ERROR_TALK_PARAM_UNTALKABLE
443
+ end
444
+ end
445
+ end
446
+ elsif player_cur_location.has_monster?(talkable_name)
447
+ player_cur_location.monsters_abounding.each do |monster|
448
+ if monster.name.eql?(talkable_name)
449
+ if monster.talkable
450
+ return self.parse("use #{talkable_name}")
451
+ else
452
+ return ERROR_TALK_PARAM_UNTALKABLE
453
+ end
454
+ end
455
+ end
456
+ elsif player_cur_location.has_boss?(talkable_name)
457
+ player_cur_location.bosses_abounding.each do |boss|
458
+ if boss.name.eql?(talkable_name)
459
+ if boss.talkable
460
+ return self.parse("use #{talkable_name}")
461
+ else
462
+ return ERROR_TALK_PARAM_UNTALKABLE
463
+ end
464
+ end
465
+ end
466
+ end
467
+ when 'use', 'u', 'open', 'o'
468
+ if param1.nil?
469
+ ERROR_USE_PARAM_MISSING
470
+ else
471
+ item_name = param1
472
+ result = nil
473
+
474
+ player_inventory = world.player.inventory
475
+
476
+ if player_inventory.contains_item?(item_name)
477
+ player_inventory.items.each do |i|
478
+ if i.name.eql?(item_name)
479
+ if i.useable
480
+ if !i.number_of_uses.nil?
481
+ if i.number_of_uses > 0
482
+ result = i.use(world)
483
+ i.number_of_uses -= 1
484
+ puts ">> #{i.name} can be used #{i.number_of_uses} more time(s)."
485
+ break
486
+ else
487
+ return ">> #{i.name} cannot be used anymore."
488
+ end
489
+ elsif i.consumable
490
+ result = i.use(world)
491
+ world.player.inventory.remove_item(i.name)
492
+ break
493
+ else
494
+ result = i.use(world)
495
+ break
496
+ end
497
+ else
498
+ return ERROR_USE_PARAM_UNUSEABLE
499
+ end
500
+ end
501
+ end
502
+ elsif player_cur_location.contains_item?(item_name)
503
+ player_cur_location.items.each do |i|
504
+ if i.name.eql?(item_name)
505
+ if i.useable
506
+ if !i.number_of_uses.nil?
507
+ if i.number_of_uses > 0
508
+ result = i.use(world)
509
+ i.number_of_uses -= 1
510
+ puts ">> #{i.name} can be used #{i.number_of_uses} more time(s)."
511
+ break
512
+ else
513
+ return ">> #{i.name} cannot be used anymore."
514
+ end
515
+ elsif i.consumable
516
+ result = i.use(world)
517
+ location.remove_item(i.name)
518
+ break
519
+ else
520
+ result = i.use(world)
521
+ break
522
+ end
523
+ else
524
+ return ERROR_USE_PARAM_UNUSEABLE
525
+ end
526
+ end
527
+ end
528
+ elsif player_cur_location.has_monster?(item_name)
529
+ player_cur_location.monsters_abounding.each do |i|
530
+ if i.name.eql?(item_name)
531
+ return i.use(world)
532
+ end
533
+ end
534
+ elsif player_cur_location.has_boss?(item_name)
535
+ player_cur_location.bosses_abounding.each do |i|
536
+ if i.name.eql?(item_name)
537
+ return i.use(world)
538
+ end
539
+ end
540
+ end
541
+
542
+ if result.nil?
543
+ ERROR_USE_PARAM_INVALID
544
+ else
545
+ case result[:type]
546
+ when 'move'
547
+ world.player.cur_coords = world.location_coords_by_name(result[:data])
548
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
549
+ world.describe(player_cur_location)
550
+ when 'move_dangerous'
551
+ dmg = rand(0..2)
552
+ puts ">> You lose #{dmg} hit point(s)." if dmg > 0
553
+ world.player.take_damage(dmg)
554
+
555
+ world.player.cur_coords = world.location_coords_by_name(result[:data])
556
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
557
+ world.describe(player_cur_location)
558
+ when 'dmg'
559
+ result = world.player.take_damage(result[:data])
560
+
561
+ if result.eql?('death')
562
+ player_death_resurrection
563
+ end
564
+ when 'rest', 'health'
565
+ world.player.heal_damage(result[:data])
566
+ return
567
+ when 'xp'
568
+ world.player.update_stats(reason: :xp, value: result[:data])
569
+ return
570
+ when 'tent'
571
+ world.player.rest(world, result[:data])
572
+ when 'action'
573
+ case result[:data]
574
+ when 'map'
575
+ world.print_map(world.player.cur_coords[:z])
576
+ end
577
+ when 'arena'
578
+ arena = Arena.new(world: world, player: world.player)
579
+ result = arena.start
580
+
581
+ if result.eql?('death')
582
+ player_death_resurrection
583
+ end
584
+ when 'item'
585
+ player_cur_location.add_item(result[:data])
586
+ return
587
+ when 'purchase'
588
+ result[:data].each do |i|
589
+ world.player.inventory.items.push(i)
590
+ end
591
+ return
592
+ else
593
+ return
594
+ end
595
+ end
596
+ end
597
+ when 'drop', 'd'
598
+ if param1.nil?
599
+ ERROR_DROP_PARAM_MISSING
600
+ else
601
+ world.player.inventory.drop_item(param1, player_cur_location)
602
+ end
603
+ when 'equip', 'eq'
604
+ if param1.nil?
605
+ ERROR_EQUIP_PARAM_MISSING
606
+ else
607
+ world.player.inventory.equip_item(param1)
608
+ end
609
+ when 'unequip', 'ue'
610
+ if param1.nil?
611
+ ERROR_UNEQUIP_PARAM_MISSING
612
+ else
613
+ world.player.inventory.unequip_item(param1)
614
+ end
615
+ when 'go', 'g'
616
+ if param1.nil?
617
+ puts ERROR_GO_PARAM_MISSING
618
+ GO_PARAMS
619
+ else
620
+ direction = param1
621
+ try_to_move_player(direction)
622
+ end
623
+ when 'n'
624
+ if param1
625
+ ERROR_DIRECTION_PARAM_INVALID
626
+ else
627
+ try_to_move_player('north')
628
+ end
629
+ when 'e'
630
+ if param1
631
+ ERROR_DIRECTION_PARAM_INVALID
632
+ else
633
+ try_to_move_player('east')
634
+ end
635
+ when 's'
636
+ if param1
637
+ ERROR_DIRECTION_PARAM_INVALID
638
+ else
639
+ try_to_move_player('south')
640
+ end
641
+ when 'w'
642
+ if param1
643
+ ERROR_DIRECTION_PARAM_INVALID
644
+ else
645
+ try_to_move_player('west')
646
+ end
647
+ when 'attack', 'a', 'fight', 'f'
648
+ if param1.nil?
649
+ if GameOptions.data['fight_completion']
650
+ if player_cur_location.has_any_monsters?
651
+ monster_param = player_cur_location.monsters_abounding[0].name
652
+ self.parse("attack #{monster_param}")
653
+ else
654
+ ERROR_ATTACK_PARAM_INVALID
655
+ end
656
+ else
657
+ ERROR_ATTACK_PARAM_MISSING
658
+ end
659
+ else
660
+ monster_name = param1
661
+ if world.has_monster_to_attack?(monster_name)
662
+ monster = player_cur_location.monster_by_name(monster_name)
663
+ result = world.player.attack(world, monster, param2)
664
+
665
+ if result.eql?('death')
666
+ return player_death_resurrection
667
+ elsif result.eql?('exit')
668
+ return 'exit'
669
+ end
670
+
671
+ unless result.nil?
672
+ case result[:type]
673
+ when 'message'
674
+ result[:data]
675
+ when 'move'
676
+ world.player.cur_coords = world.location_coords_by_name(result[:data])
677
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
678
+ world.describe(player_cur_location)
679
+ end
680
+ end
681
+ else
682
+ ERROR_ATTACK_PARAM_INVALID
683
+ end
684
+ end
685
+ when 'breakthru', 'br'
686
+ if world.player.special_abilities.include?(:breakthru)
687
+ if param1.nil?
688
+ return ERROR_BREAKTHRU_PARAM_MISSING
689
+ else
690
+ place_to_match = tokens[1..tokens.length].join(' ').downcase
691
+ locations = []
692
+ world.locations.each do |l|
693
+ locations << l.name.downcase
694
+ end
695
+ if locations.include?(place_to_match)
696
+ world.player.cur_coords = world.location_coords_by_name(place_to_match)
697
+ else
698
+ return ERROR_BREAKTHRU_PARAM_INVALID
699
+ end
700
+ end
701
+
702
+ # stats
703
+ world.player.movements_made += 1
704
+
705
+ Animation.run(phrase: '** BREAK THROUGH! **')
706
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
707
+ return world.describe(player_cur_location)
708
+ else
709
+ ERROR_BREAKTHRU_INEXPERIENCED
710
+ end
711
+ when 'change', 'ch'
712
+ if param1.nil?
713
+ puts ERROR_CHANGE_PARAM_MISSING
714
+ CHANGE_PARAMS
715
+ else
716
+ case param1
717
+ when 'name'
718
+ world.player.modify_name
719
+ else
720
+ ERROR_CHANGE_PARAM_INVALID
721
+ end
722
+ end
723
+ when 'help', 'h', '?', '??', '???'
724
+ list_commands
725
+ when 'version', 'v'
726
+ Gemwarrior::VERSION
727
+ when 'checkupdate', 'cu'
728
+ 'checkupdate'
729
+ when 'quit', 'exit', 'q', 'x'
730
+ print 'You sure you want to quit? (y/n) '
731
+ answer = gets.chomp.downcase
732
+
733
+ case answer
734
+ when 'y', 'yes'
735
+ puts QUIT_MESSAGE.colorize(:yellow)
736
+ return 'exit'
737
+ else
738
+ puts RESUME_MESSAGE.colorize(:green)
739
+ end
740
+ when 'quit!', 'exit!', 'qq', 'xx'
741
+ puts QUIT_MESSAGE.colorize(:yellow)
742
+ return 'exit'
743
+ else
744
+ return
745
+ end
746
+ end
747
+
748
+ private
749
+
750
+ def try_to_move_player(direction)
751
+ if world.can_move?(direction)
752
+ world.player.go(world, direction)
753
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
754
+ player_cur_location.checked_for_monsters = false
755
+
756
+ if player_cur_location.name.include?('pain_quarry')
757
+ if player_cur_location.has_boss?('garynetty')
758
+ roll = rand(0..100) + world.player.dexterity
759
+ roll_display = roll < 25 ? "#{roll}".colorize(:red) : "#{roll}".colorize(:green)
760
+ puts "[Pain Quarry Garynetty Roll: #{roll_display}]" if GameOptions.data['debug_mode']
761
+ if roll < 25
762
+ self.parse("attack garynetty is_ambush")
763
+ else
764
+ puts 'You nearly got attacked by a vicious Garynetty! Be careful, your next move might not be as lucky.'.colorize(:yellow)
765
+ end
766
+ end
767
+ end
768
+
769
+ world.describe(player_cur_location)
770
+ else
771
+ return ERROR_GO_PARAM_INVALID.colorize(:red)
772
+ end
773
+ end
774
+
775
+ def player_death_resurrection
776
+ Audio.play_synth(:player_resurrection)
777
+
778
+ puts 'Somehow, though, your adventure does not end here!'.colorize(:yellow)
779
+ puts 'Instead, you are whisked back home via some magical force.'.colorize(:yellow)
780
+ puts 'A bit worse for the weary and somewhat poorer, but you are ALIVE!'.colorize(:yellow)
781
+ puts
782
+
783
+ world.player.hp_cur = 1
784
+ world.player.rox -= (world.player.rox * 0.1).to_i
785
+ if world.player.rox < 0
786
+ world.player.rox = 0
787
+ end
788
+ world.player.cur_coords = world.location_coords_by_name('Home')
789
+ player_cur_location = world.location_by_coords(world.player.cur_coords)
790
+ world.describe(player_cur_location)
791
+ world.player.deaths += 1
792
+ return
793
+ end
794
+
795
+ def list_commands
796
+ i = 0
797
+ Hr.print('=')
798
+ puts ' COMMAND | ALIAS | DESCRIPTION '
799
+ Hr.print('=')
800
+ commands.each do |cmd|
801
+ puts " #{cmd.ljust(11)} | #{aliases[i].ljust(5)} | #{cmd_descriptions[i]}"
802
+ i += 1
803
+ end
804
+ Hr.print('=')
805
+
806
+ if GameOptions.data['debug_mode']
807
+ puts ' DEBUG COMMANDS'
808
+ Hr.print('=')
809
+ i = 0
810
+ devcommands.each do |cmd|
811
+ puts " #{cmd.ljust(11)} | #{devaliases[i].ljust(5)} | #{devcmd_descriptions[i]}"
812
+ i += 1
813
+ end
814
+ Hr.print('=')
815
+ end
816
+ end
817
+
818
+ def input_valid?(input)
819
+ tokens = input.split
820
+ command = tokens[0]
821
+ commands_and_aliases = commands | aliases | extras
822
+
823
+ if GameOptions.data['debug_mode']
824
+ commands_and_aliases = commands_and_aliases | devcommands | devaliases | devextras
825
+ end
826
+
827
+ if commands_and_aliases.include?(command.downcase)
828
+ if tokens.size.between?(1, 4)
829
+ return true
830
+ end
831
+ elsif tokens.empty?
832
+ return true
833
+ end
834
+ end
835
+ end
836
+ end