gemwarrior 0.15.10 → 0.15.11

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.
@@ -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