poor-pokemon-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 71a2535678f62aa37ce2ea61459c07bc293c79b9
4
+ data.tar.gz: 98be132e33af240a9ed13348841e467909b40055
5
+ SHA512:
6
+ metadata.gz: a4ad6f238655a8a9d04d41a7e881e715191bf0e7c945f999d263a57eca5c4a76dbd7c6cfc96dc58bd24c0bce620878ea666f55b86ebfbf1fe4a0dd7241e2c901
7
+ data.tar.gz: 3438f2ae091c97b176b0b727aadc4a40fecf7b03c30d7f799e944c63bfe728c69e86bf80493c4a17019902a544e3f3b676cbfeb11ee6b6f947f3f157b868d215
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "examples/now-playing-cli-gem"]
2
+ path = examples/now-playing-cli-gem
3
+ url = git@github.com:learn-co-curriculum/now-playing-cli-gem.git
data/.learn ADDED
@@ -0,0 +1,8 @@
1
+ tags:
2
+ - cli
3
+ - gem
4
+ - oo
5
+ languages:
6
+ - ruby
7
+ resources:
8
+ live_assessment: true
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,37 @@
1
+ # Contributing to Learn.co Curriculum
2
+
3
+ We're really exited that you're about to contribute to the [open curriculum](https://learn.co/content-license) on [Learn.co](https://learn.co). If this is your first time contributing, please continue reading to learn how to make the most meaningful and useful impact possible.
4
+
5
+ ## Raising an Issue to Encourage a Contribution
6
+
7
+ If you notice a problem with the curriculum that you believe needs improvement
8
+ but you're unable to make the change yourself, you should raise a Github issue
9
+ containing a clear description of the problem. Include relevant snippets of
10
+ the content and/or screenshots if applicable. Curriculum owners regularly review
11
+ issue lists and your issue will be prioritized and addressed as appropriate.
12
+
13
+ ## Submitting a Pull Request to Suggest an Improvement
14
+
15
+ If you see an opportunity for improvement and can make the change yourself go
16
+ ahead and use a typical git workflow to make it happen:
17
+
18
+ * Fork this curriculum repository
19
+ * Make the change on your fork, with descriptive commits in the standard format
20
+ * Open a Pull Request against this repo
21
+
22
+ A curriculum owner will review your change and approve or comment on it in due
23
+ course.
24
+
25
+ # Why Contribute?
26
+
27
+ Curriculum on Learn is publicly and freely available under Learn's
28
+ [Educational Content License](https://learn.co/content-license). By
29
+ embracing an open-source contribution model, our goal is for the curriculum
30
+ on Learn to become, in time, the best educational content the world has
31
+ ever seen.
32
+
33
+ We need help from the community of Learners to maintain and improve the
34
+ educational content. Everything from fixing typos, to correcting
35
+ out-dated information, to improving exposition, to adding better examples,
36
+ to fixing tests—all contributions to making the curriculum more effective are
37
+ welcome.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specified gem's dependencies in poor-pokemon-cli-gem.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ #Learn.co Educational Content License
2
+
3
+ Copyright (c) 2015 Flatiron School, Inc
4
+
5
+ The Flatiron School, Inc. owns this Educational Content. However, the Flatiron School supports the development and availability of educational materials in the public domain. Therefore, the Flatiron School grants Users of the Flatiron Educational Content set forth in this repository certain rights to reuse, build upon and share such Educational Content subject to the terms of the Educational Content License set forth [here](http://learn.co/content-license) (http://learn.co/content-license). You must read carefully the terms and conditions contained in the Educational Content License as such terms govern access to and use of the Educational Content.
6
+
7
+ Flatiron School is willing to allow you access to and use of the Educational Content only on the condition that you accept all of the terms and conditions contained in the Educational Content License set forth [here](http://learn.co/content-license) (http://learn.co/content-license). By accessing and/or using the Educational Content, you are agreeing to all of the terms and conditions contained in the Educational Content License. If you do not agree to any or all of the terms of the Educational Content License, you are prohibited from accessing, reviewing or using in any way the Educational Content.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # Poor-Pokemon-CLI-Gem
2
+ ###Poorly Designed Pokemon Remake (PDPR)!
3
+
4
+ ## Overview
5
+ In this simple CLI gem game, the player selects whatever pokemon they want from their pokedex to be added to their roster of 6, and then battles against an opponent, "Poorly Designed Boss".
6
+
7
+ The pokedex is constructed from this website (http://pokedream.com/pokedex/pokemon?display=gen1) and parsed using the gem Nokogiri.
8
+
9
+
10
+ ## Installation
11
+ You can install this gem via `gem install poor-pokemon-cli`. The `poor-pokemon` CLI will be installed and you can run `poor-pokemon` to start playing the game right in your command line.
12
+
13
+ ## Usage
14
+ Run: `poor-pokemon` after installing the gem.
15
+
16
+ ## Contributing
17
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mahdiASC/cli-data-gem-assessment-v-000. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
18
+
19
+ ## License
20
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/bin/poor-pokemon ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/poor-pokemon"
4
+ PoorPokemon::CLI.new.call
@@ -0,0 +1,12 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'pry'
4
+
5
+ require_relative "../lib/poor-pokemon/basePlayer"
6
+ require_relative "../lib/poor-pokemon/pokedexPokemon"
7
+ require_relative "../lib/poor-pokemon/pokedex"
8
+ require_relative "../lib/poor-pokemon/pokemon"
9
+ require_relative "../lib/poor-pokemon/player"
10
+ require_relative "../lib/poor-pokemon/enemy"
11
+ require_relative "../lib/poor-pokemon/move"
12
+ require_relative "../lib/poor-pokemon/cli"
@@ -0,0 +1,4 @@
1
+ #Not sure what this module is for, but its everywhere -.-
2
+ module PoorPokemon
3
+ end
4
+ require_relative '../config/environment'
@@ -0,0 +1,14 @@
1
+ class PoorPokemon::BasePlayer
2
+ attr_accessor :roster, :currentPokemon
3
+
4
+ def allDead?
5
+ # returns true if no more pokemon left to play
6
+ !@roster.any?{|pokemon| pokemon.alive?}
7
+ end
8
+
9
+ def changeCurrent(number)
10
+ #changes currentPokemon to the pokemon in roster under "number" index
11
+ @currentPokemon = @roster[number]
12
+ end
13
+
14
+ end
@@ -0,0 +1,420 @@
1
+ class PoorPokemon::CLI
2
+ attr_accessor :player, :enemy, :pokedex, :difficulty
3
+
4
+ def initialize
5
+ @player = PoorPokemon::Player.new()
6
+ @pokedex = PoorPokemon::Pokedex.new()
7
+ end
8
+
9
+ def call
10
+ intro
11
+ difficulty
12
+ pokedexSelection
13
+ beginFight
14
+ declareWinner
15
+ restart
16
+ end
17
+
18
+ def intro
19
+ puts 'Welcome to Poorly Designed Pokemon Remake (PDPR)!'
20
+ puts 'I\'ve scraped Pokemon and their stats from a website and created a pokedex.'
21
+ puts 'You\'ll battle \'Poorly Designed Boss\', who has the 6 best pokemon with perfect stats!'
22
+ puts 'To battle him, you\'ll select 6 pokemon from the pokedex to add to your roster'
23
+ puts 'Then you\'ll take turns attacking his pokemon with yours.'
24
+ puts 'Unfortunately, \'Poorly Designed Boss\' has sabatoged your pokemon by giving them random attacks and imperfect stats!'
25
+ puts 'Can you still defeat him, despite being at a disadvantage!?'
26
+ puts 'Good luck, and have fun!'
27
+ end
28
+
29
+ def difficulty
30
+ #Sets difficulty of Enemy AI
31
+ userInput = ""
32
+ choices = ['e','h','easy','hard']
33
+ until choices.include?(userInput) do
34
+ puts "Select Difficulty: (e)asy (h)ard"
35
+ userInput = gets.strip.downcase
36
+ end
37
+ @difficulty = userInput
38
+ if userInput == "e" || userInput == "easy"
39
+ @enemy = PoorPokemon::Enemy.new(@pokedex.randSix(true))
40
+ fillMoves(@enemy, "easy")
41
+ elsif userInput == "h" || userInput == "hard"
42
+ @enemy = PoorPokemon::Enemy.new(@pokedex.bestSix(true))
43
+ fillMoves(@enemy, "hard")
44
+ end
45
+ end
46
+
47
+ def fillMoves(char, diff=nil)
48
+ #fills char's pokemon roster with appropriate moves
49
+ #moves are different for enemy
50
+ if char.is_a?(PoorPokemon::Player)
51
+ char.roster.each{|pokemon|
52
+ output = []
53
+ output.push(PoorPokemon::Move.new("Normal Attack",randAtt(45),"Normal",30))
54
+ output.push(PoorPokemon::Move.new("Big Normal Attack",randAtt(110),"Normal",10))
55
+ output.push(PoorPokemon::Move.new("Special Attack",randAtt(70),randType,20))
56
+ output.push(PoorPokemon::Move.new("Big Special Attack",randAtt(100),randType,5))
57
+ pokemon.moves = output
58
+ }
59
+ else
60
+ #Enemy player
61
+ if diff == "easy"
62
+ char.roster.each{|pokemon|
63
+ output = []
64
+ output.push(PoorPokemon::Move.new("Normal Attack",randAtt(45),"Normal",30))
65
+ output.push(PoorPokemon::Move.new("Big Normal Attack",randAtt(110),"Normal",10))
66
+ output.push(PoorPokemon::Move.new("Special Attack",randAtt(70),randType,20))
67
+ output.push(PoorPokemon::Move.new("Big Special Attack",randAtt(100),randType,5))
68
+ pokemon.moves = output
69
+ }
70
+ elsif diff == "hard"
71
+ char.roster.each{|pokemon|
72
+ output=[]
73
+ output.push(PoorPokemon::Move.new("Normal Attack",40,"Normal",30))
74
+ output.push(PoorPokemon::Move.new("Big Normal Attack",100,"Normal",10))
75
+ output.push(PoorPokemon::Move.new("Special Attack",65,pokemon.type1,20))
76
+ output.push(PoorPokemon::Move.new("Big Special Attack",90,pokemon.type1,5))
77
+ pokemon.moves = output
78
+ }
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ def randType
85
+ ["Bug","Dragon","Ice","Fighting","Fire","Flying","Grass","Ghost","Ground","Electric","Normal","Poison","Psychic","Rock","Water"].sample
86
+ end
87
+
88
+ def randAtt(num)
89
+ var = (num * 0.1).round
90
+ rand(var)+num-var
91
+ end
92
+
93
+ def displayPokemon(pokeGroup)
94
+ #pokeGroup is an array of PokedexPokemon
95
+ #must have at least 1 item in array
96
+ #Displays the group for the user
97
+ maxNameLength = pokeGroup.sort{|a,b| a.name.length<=>b.name.length}.last.name.length+5
98
+
99
+ pokeGroup.each_index{|i|
100
+ name = "#{i+1}. #{pokeGroup[i].name.capitalize}"
101
+ until name.length >= maxNameLength do
102
+ name = name + " "
103
+ end
104
+ types = pokeGroup[i].type2 != "" ? pokeGroup[i].type1.capitalize + "+" + pokeGroup[i].type2.capitalize : pokeGroup[i].type1.capitalize
105
+ puts "#{name} TYPE:#{types} HP:#{pokeGroup[i].hp} ATT:#{pokeGroup[i].att} DEF:#{pokeGroup[i].def} SPD:#{pokeGroup[i].spd} SP-ATT:#{pokeGroup[i].spAtt} SP-DEF:#{pokeGroup[i].spDef}"
106
+ }
107
+ end
108
+
109
+ def pokedexSelection
110
+ #player will begin selecting desired pokemon from pokedex
111
+ #Ends when player has full roster
112
+ until @player.roster.length>=6 do
113
+ showPlayerRoster
114
+ playerSelection
115
+ end
116
+ showPlayerRoster
117
+ fillMoves(@player)
118
+ end
119
+
120
+ def showPlayerRoster
121
+ puts "YOUR ROSTER:"
122
+ if @player.roster.length>0
123
+ @player.roster.each_index{|i|
124
+ puts "#{i+1}. #{@player.roster[i].name.capitalize}"
125
+ }
126
+ else
127
+ puts "{There are no pokemon in your roster}"
128
+ end
129
+ sepLine
130
+ end
131
+
132
+ def playerSelection
133
+ userInput = ""
134
+ until ["1","2"].include?(userInput) do
135
+ puts "Select a pokemon from the Pokedex, to add to your roster (#{6-@player.roster.length} left to pick)"
136
+ puts "Options: (1)List all pokemon (2)Search by name"
137
+ userInput = gets.strip
138
+ case userInput
139
+ when "1"
140
+ searchResults = @pokedex.pokeList #full list of pokemon
141
+ when "2"
142
+ searchResults = []
143
+ until searchResults.length>0 do
144
+ puts 'Type in a name or partial name to search: '
145
+ searchInput = gets.strip
146
+ searchResults = @pokedex.searchName(searchInput)
147
+ if searchResults.length<1
148
+ puts "{No results found. Try again.}"
149
+ end
150
+ end
151
+ else
152
+ invalid
153
+ end
154
+ end
155
+ sepLine
156
+ # Either list all pokemon, or allow for search by name
157
+ displayPokemon(searchResults)
158
+ sepLine
159
+ #User selects pokemon
160
+ validSelection = ""
161
+ until (1..searchResults.length).map{|x| x.to_s}.include?(validSelection) do
162
+ puts "Select the number of the pokemon to add to your roster"
163
+ validSelection=gets.strip
164
+ end
165
+ sepLine
166
+ @player.add(searchResults[validSelection.to_i-1].clone)
167
+ end
168
+
169
+ def sepLine
170
+ puts "____________________"
171
+ end
172
+
173
+ def invalid
174
+ puts "{Invalid selection. Try again.}"
175
+ end
176
+
177
+ def beginFight
178
+ puts "\'Poorly Designed Boss\' wants to battle!"
179
+ displayBothRosters
180
+ playerSwitch
181
+ until @player.allDead? || @enemy.allDead? do
182
+ turnOrder
183
+ end
184
+ end
185
+
186
+ def displayBothRosters
187
+ maxLength = @player.roster.sort{|a,b| a.name.length<=>b.name.length}.last.name.length+2
188
+ title = "You"
189
+ until title.length >= maxLength do
190
+ title = " " + title
191
+ end
192
+ puts title + " || Enemy"
193
+ sepLine
194
+ @player.roster.each_index{|i|
195
+ text = @player.roster[i].name.upcase
196
+ until text.length >= maxLength do
197
+ text = " " + text
198
+ end
199
+ typeText = @enemy.roster[i].type2!="" ? " (#{@enemy.roster[i].type1.capitalize}+#{@enemy.roster[i].type2.capitalize})" : " (#{@enemy.roster[i].type1.capitalize})"
200
+ text = text + " || " + @enemy.roster[i].name.upcase + typeText
201
+ puts text
202
+ }
203
+
204
+ end
205
+
206
+ def declareWinner
207
+ if @player.allDead?
208
+ puts "You lost!"
209
+ else
210
+ puts "You won!"
211
+ end
212
+ end
213
+
214
+ def turnOrder
215
+ #decides turn order based on each player's current pokemon's speed
216
+ #in event of tie, random
217
+ if @player.currentPokemon.spd == @enemy.currentPokemon.spd
218
+ if rand()>0.5
219
+ playerTurn
220
+ if @enemy.currentPokemon.alive?
221
+ enemyTurn
222
+ end
223
+ else
224
+ enemyTurn
225
+ if @player.currentPokemon.alive?
226
+ playerTurn
227
+ end
228
+ end
229
+ elsif @player.currentPokemon.spd>@enemy.currentPokemon.spd
230
+ playerTurn
231
+ if @enemy.currentPokemon.alive?
232
+ enemyTurn
233
+ end
234
+ elsif @player.currentPokemon.spd<@enemy.currentPokemon.spd
235
+ enemyTurn
236
+ if @player.currentPokemon.alive?
237
+ playerTurn
238
+ end
239
+ end
240
+
241
+ #switch if any dead and player still has usable pokemon
242
+ if !@player.currentPokemon.alive?
243
+ puts "Your #{@player.currentPokemon.name.upcase} fainted!"
244
+ if !@player.allDead?
245
+ playerSwitch
246
+ end
247
+ end
248
+ if !@enemy.currentPokemon.alive?
249
+ puts "Enemy #{@enemy.currentPokemon.name.upcase} fainted!"
250
+ if !@enemy.allDead?
251
+ @enemy.switch
252
+ puts "Enemy sent out #{@enemy.currentPokemon.name.upcase}!"
253
+ end
254
+ end
255
+
256
+ if !gameWon?
257
+ currentStatus
258
+ end
259
+ end
260
+
261
+ def playerTurn
262
+ puts "###Your Turn###"
263
+ typeText = @player.currentPokemon.type2 != "" ? "#{@player.currentPokemon.type1}+#{@player.currentPokemon.type2}" : "#{@player.currentPokemon.type1}"
264
+ puts "Current Pokemon: #{@player.currentPokemon.name.upcase} HP:#{@player.currentPokemon.hp} TYPE: #{typeText.upcase}"
265
+ typeText = @enemy.currentPokemon.type2 != "" ? "#{@enemy.currentPokemon.type1}+#{@enemy.currentPokemon.type2}" : "#{@enemy.currentPokemon.type1}"
266
+ puts "Enemy Pokemon: #{@enemy.currentPokemon.name.upcase} HP:#{@enemy.currentPokemon.hp} TYPE: #{typeText.upcase}"
267
+ sepLine
268
+ puts "What would you like to do? (a)ttack (s)witch"
269
+ userInput = ""
270
+ choices = ["a","attack","s","switch"]
271
+ until choices.include?(userInput) do
272
+ userInput = gets.strip.downcase
273
+ if (userInput == "s" || userInput == "switch")
274
+ playerSwitch
275
+ elsif(userInput == "a" || userInput == "attack")
276
+ playerAttacks(@enemy.currentPokemon)
277
+ else
278
+ invalid
279
+ end
280
+ end
281
+ sepLine
282
+ end
283
+
284
+ def playerSwitch
285
+ #Player switches current pokemon from roster
286
+ sepLine
287
+ if @player.currentPokemon
288
+ puts "Select Pokemon from your roster to switch to:"
289
+ else
290
+ puts "Select Pokemon from your roster to start with:"
291
+ end
292
+ userInput = "0"
293
+ until @player.valids.include?(@player.roster[userInput.to_i-1]) && userInput != "0" do
294
+ showPlayerSwitchRoster
295
+ userInput = gets.strip
296
+ if !@player.valids.include?(@player.roster[userInput.to_i-1])
297
+ invalid
298
+ end
299
+ end
300
+ if @player.currentPokemon
301
+ puts "#{@player.currentPokemon.name.upcase} returns!"
302
+ end
303
+ @player.changeCurrent(userInput.to_i-1)
304
+ puts "#{@player.currentPokemon.name.upcase} enters the battle!"
305
+ end
306
+
307
+ def showPlayerSwitchRoster
308
+ maxLength = @player.roster.sort{|a,b| a.name.length<=>b.name.length}.last.name.length+5
309
+
310
+ @player.roster.each_index{|i|
311
+ health = @player.roster[i].alive? ? @player.roster[i].hp.to_s + " HP" : "FAINTED!"
312
+ text = "#{i+1}. #{@player.roster[i].name.upcase}"
313
+ until text.length >= maxLength do
314
+ text = text + " "
315
+ end
316
+ if health !="FAINTED!"
317
+ puts "#{text}| STATUS: #{health} spAtt1:#{@player.roster[i].moves[2].name.match(/(?<=\().*(?=\))/)[0].upcase}/PP #{@player.roster[i].moves[2].pp} spAtt2:#{@player.roster[i].moves[3].name.match(/(?<=\().*(?=\))/)[0].upcase}/PP #{@player.roster[i].moves[3].pp}"
318
+ else
319
+ puts "#{text}| STATUS: #{health}"
320
+ end
321
+ }
322
+ sepLine
323
+ end
324
+
325
+ def playerAttacks(enemyPokemon)
326
+ #gives user options on what move to attack with
327
+ sepLine
328
+ if @player.currentPokemon.canAttack?
329
+ userInput = "0"
330
+ availMoves = @player.currentPokemon.usableMoves
331
+ until availMoves.include?(@player.currentPokemon.moves[userInput.to_i-1]) && userInput!="0" do
332
+ puts "Which move should #{@player.currentPokemon.name.capitalize} use?"
333
+ maxLength = @player.currentPokemon.moves.sort{|a,b| a.name.length<=>b.name.length}.last.name.length+5
334
+ @player.currentPokemon.moves.each_index{|i|
335
+ move = @player.currentPokemon.moves[i]
336
+ text = "#{i+1}. #{move.name.upcase}"
337
+ until text.length >= maxLength do
338
+ text = text + " "
339
+ end
340
+ puts "#{text} > PP: #{move.pp}"
341
+ }
342
+ userInput = gets.strip
343
+ if !availMoves.include?(@player.currentPokemon.moves[userInput.to_i-1]) && userInput!="0"
344
+ invalid
345
+ end
346
+ end
347
+ move = @player.currentPokemon.moves[userInput.to_i-1]
348
+ puts "#{@player.currentPokemon.name.upcase} used #{move.name.split(" (")[0].upcase} (#{move.type})!"
349
+ puts dmgText(@player.currentPokemon.attacks(enemyPokemon,move))
350
+ else
351
+ #current pokemon is out of PP for all moves, defaults to "Struggle"
352
+ struggle = PoorPokemon::Move.new("Struggle",40,"Normal",99)
353
+ puts "#{@player.currentPokemon.name.upcase} is out of moves!"
354
+ puts "#{@player.currentPokemon.name.upcase} used STRUGGLE! #{struggle.type}"
355
+ puts dmgText(@player.currentPokemon.attacks(enemyPokemon,struggle))
356
+ end
357
+ end
358
+
359
+ def dmgText(dmgArray)
360
+ #depending on the number, will evaluate the effectiveness of the attack
361
+ #returns a string to communicate that effectiveness
362
+ dmg = dmgArray[0]
363
+ num = dmgArray[1]
364
+
365
+ if num == 0
366
+ output = "No effect!"
367
+ elsif num == 0.5 || num == 0.25
368
+ output = "It's not very effective."
369
+ elsif num == 2
370
+ output = "It's super-effective!"
371
+ elsif num == 4
372
+ output = "Critical hit!" #Not a true critical hit
373
+ else
374
+ output = "It hit!"
375
+ end
376
+ output + " (#{dmg} dmg)"
377
+ end
378
+
379
+ def enemyTurn
380
+ puts "###Enemy Turn###"
381
+ if @enemy.currentPokemon.canAttack?
382
+ attackArray = @enemy.attacks(@player.currentPokemon,@difficulty)
383
+ puts "#{@enemy.currentPokemon.name.upcase} used #{attackArray[1].name.split(" (")[0].upcase} (#{attackArray[1].type})!"
384
+ puts dmgText(attackArray[0])
385
+ else
386
+ #current pokemon is out of PP for all moves, defaults to "Struggle"
387
+ struggle = PoorPokemon::Move.new("Struggle",40,"Normal",99)
388
+ attackArray = @enemy.attacks(@player.currentPokemon, @difficulty, struggle)
389
+ puts "Enemy #{@enemy.currentPokemon.name.upcase} is out of moves!"
390
+ puts "Enemy #{@enemy.currentPokemon.name.upcase} used STRUGGLE #{struggle.type}!"
391
+ puts dmgText(attackArray[0])
392
+ end
393
+ sepLine
394
+ end
395
+
396
+ def currentStatus
397
+ #prints current status for both sides
398
+ puts "Your #{@player.currentPokemon.name.capitalize} has #{@player.currentPokemon.hp} HP"
399
+ puts "Enemy #{@enemy.currentPokemon.name.capitalize} has #{@enemy.currentPokemon.hp} HP"
400
+ sepLine
401
+ end
402
+
403
+ def gameWon?
404
+ @enemy.allDead? || @player.allDead?
405
+ end
406
+
407
+ def restart
408
+ sepLine
409
+ puts "Would you like to play again? (y)es (n)o"
410
+ choices = ["y","n","yes","no"]
411
+ userInput = ''
412
+ until choices.include?(userInput) do
413
+ userInput = gets.strip.downcase
414
+ end
415
+
416
+ if(userInput == "y" || userInput == "yes")
417
+ call
418
+ end
419
+ end
420
+ end
@@ -0,0 +1,27 @@
1
+ class PoorPokemon::Enemy < PoorPokemon::BasePlayer
2
+ def initialize(pokeGroup)
3
+ @roster = pokeGroup
4
+ @currentPokemon = @roster[0]
5
+ end
6
+
7
+ def switch
8
+ #switches current pokemon (should be dead) for another valid pokemon
9
+ @currentPokemon = @roster.select{|pokemon|pokemon.alive?}.sample
10
+ end
11
+
12
+ def attacks(oppPokemon, diff, move=nil)
13
+ #determines how enemy AI attacks depending on difficulty
14
+ if move
15
+ dmg = @currentPokemon.attacks(oppPokemon, move)
16
+ else
17
+ if diff == "easy" || diff =='e'
18
+ move = @currentPokemon.usableMoves.sample
19
+ dmg = @currentPokemon.attacks(oppPokemon, move)
20
+ elsif diff == "hard" || diff =="h"
21
+ move = @currentPokemon.usableMoves.sort{|moveA,moveB| moveA.dmg<=>moveB.dmg}.last
22
+ dmg = @currentPokemon.attacks(oppPokemon, move)
23
+ end
24
+ end
25
+ [dmg, move]
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ class PoorPokemon::Move
2
+ attr_accessor :name, :dmg, :type, :pp
3
+
4
+ def initialize (name, dmg, type, pp)
5
+ @name = "#{name} (#{type})"
6
+ @dmg = dmg
7
+ @type = type
8
+ @pp = pp
9
+ end
10
+
11
+ def usable?
12
+ #returns true if move has enough PP to be used
13
+ @pp>0
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class PoorPokemon::Player < PoorPokemon::BasePlayer
2
+ def initialize
3
+ @roster = []
4
+ end
5
+
6
+ def add(pokemon)
7
+ @roster.push(pokemon)
8
+ end
9
+
10
+ def valids
11
+ #returns array of living pokemon
12
+ @roster.select{|pokemon|pokemon.alive?}
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ class PoorPokemon::Pokedex
2
+ attr_accessor :pokeList
3
+ def initialize
4
+ # Pokemon database
5
+ # http://pokedream.com/pokedex/pokemon?display=gen1
6
+ pokemonDoc = Nokogiri::HTML(open("http://pokedream.com/pokedex/pokemon?display=gen1"))
7
+ @pokeList = pokemonDoc.css(".UILinkedTableRow").map{ |row|
8
+ rowData = row.children().map{ |col|
9
+ if col.attribute("class")
10
+ col.attribute("class").value
11
+ else
12
+ col.text()
13
+ end
14
+ }.reject{|val| val == "\n" || val == "---"}
15
+ rowData
16
+ }.map{|row|
17
+ PoorPokemon::PokedexPokemon.new(row)
18
+ }
19
+ end
20
+
21
+ def bestSix(flag=false)
22
+ #flag is for enemy to have perfect stats
23
+ @pokeList.sort{|pokemonA,pokemonB| pokemonB.totalStats <=> pokemonA.totalStats}.take(6).map{|pokemon|pokemon.clone(flag)}
24
+ end
25
+
26
+ def randSix(flag=false)
27
+ #flag is for enemy to have perfect stats
28
+ randArray = []
29
+ 6.times do
30
+ randArray.push(@pokeList.sample.clone(flag))
31
+ end
32
+ randArray
33
+ end
34
+
35
+ def searchName(word)
36
+ @pokeList.select{|pokemon| pokemon.name[word]}
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,14 @@
1
+ class PoorPokemon::PokedexPokemon
2
+ attr_accessor :name, :num, :type1, :type2, :hp, :att, :def, :spAtt, :spDef, :spd, :totalStats
3
+
4
+ def initialize(arr)
5
+ @name, @num, @type1, @type2, @hp, @att, @def, @spAtt, @spDef, @spd, @totalStats = arr
6
+ end
7
+
8
+ def clone (flag=false)
9
+ # creates a copy of this pokedexPokemon object as a pokemon object
10
+ # moves is an array of moves
11
+ #flag is for enemy to have perfect stats
12
+ return PoorPokemon::Pokemon.new([@name, @type1, @type2, @hp.to_i, @att.to_i, @def.to_i, @spAtt.to_i, @spDef.to_i, @spd.to_i], flag)
13
+ end
14
+ end
@@ -0,0 +1,190 @@
1
+ class PoorPokemon::Pokemon
2
+ attr_accessor :name, :type1, :type2, :hp, :att, :def, :spAtt, :spDef, :spd, :moves
3
+
4
+
5
+ def initialize(arr, flag=false)
6
+ #flag is for enemy to have perfect stats
7
+ @name, @type1, @type2, @hp, @att, @def, @spAtt, @spDef, @spd = arr
8
+
9
+ #Determines proper stats
10
+ #https://www.dragonflycave.com/mechanics/stats
11
+ #Individual stats (0-15)
12
+ atkIV = flag ? 15: rand(15)
13
+ @att += atkIV
14
+ @att = @att*2+68
15
+
16
+
17
+ defIV = flag ? 15:rand(15)
18
+ @def += defIV
19
+ @def = @def*2+68
20
+
21
+ spdIV = flag ? 15:rand(15)
22
+ @spd += spdIV
23
+ @spd = @spd*2+68
24
+
25
+ spIV = flag ? 15:rand(15)
26
+ @spAtt += spIV
27
+ @spAtt = @spAtt*2+68
28
+ @spDef += spIV
29
+ @spDef = @spDef*2+68
30
+
31
+ #how HP and IV are connected
32
+ if atkIV%2==1
33
+ @hp += 8
34
+ end
35
+
36
+ if defIV%2==1
37
+ @hp += 4
38
+ end
39
+
40
+ if spdIV%2==1
41
+ @hp += 2
42
+ end
43
+
44
+ if spIV%2==1
45
+ @hp += 1
46
+ end
47
+ @hp = @hp*2+110
48
+
49
+ @moves = []
50
+ end
51
+
52
+ def alive?
53
+ @hp > 0
54
+ end
55
+
56
+ def attacks(oppPokemon, move)
57
+ #dmg calculations
58
+ attackStat = ["normal", "fighting", "flying", "poison", "ground", "rock", "bug", "ghost"].include?(move.type) ? @att : @spAtt
59
+ attackPower = move.dmg
60
+ defenseStat = ["normal", "fighting", "flying", "poison", "ground", "rock", "bug", "ghost"].include?(move.type) ? oppPokemon.def : oppPokemon.spDef
61
+ randNum = rand(255-217)+217
62
+ stab = move.type == @type1 || move.type == @type2 ? 1.5 : 1
63
+ weakResist = calcWeakResist(oppPokemon,move)
64
+
65
+ #dmg equation
66
+ damageTotal = (((((42 * attackStat.to_f * (attackPower.to_f/defenseStat.to_f))/50)+2)*stab.to_f*weakResist.to_f)*randNum.to_f/255).floor
67
+
68
+ #applying dmg
69
+ move.pp -= 1
70
+ oppPokemon.hp -= damageTotal
71
+ if oppPokemon.hp < 0
72
+ oppPokemon.hp = 0 #just in case HP checked
73
+ end
74
+ [damageTotal,weakResist]
75
+ end
76
+
77
+ def calcWeakResist(oppPokemon,move, typeInput=nil)
78
+ #returns multiplier for attack effectiveness
79
+ #0.25, 0.5, 1, 2, or 4
80
+ # http://unrealitymag.com/wp-content/uploads/2014/11/rby-rules.jpg
81
+ type = (typeInput || oppPokemon.type1).downcase
82
+ output = 1; #number returned as modifier
83
+ case move.type.downcase
84
+ when 'normal'
85
+ if ['ghost'].include?(type)
86
+ output *= 0
87
+ end
88
+ when 'bug'
89
+ if ['fire','flying',"rock"].include?(type)
90
+ output*=0.5
91
+ elsif ['grass','poison',"psychic"].include?(type)
92
+ output*=2
93
+ end
94
+ when 'dragon'
95
+ #No effectiveness
96
+ when 'ice'
97
+ if ['ice','water'].include?(type)
98
+ output*=0.5
99
+ elsif ['dragon','flying','grass','ground'].include?(type)
100
+ output*=2
101
+ end
102
+ when 'fighting'
103
+ if ['flying','psychic'].include?(type)
104
+ output*=0.5
105
+ elsif ['ice','normal','rock'].include?(type)
106
+ output*=2
107
+ elsif ['ghost'].include?(type)
108
+ output*=0
109
+ end
110
+ when 'fire'
111
+ if ['rock','water'].include?(type)
112
+ output*=0.5
113
+ elsif ['bug','grass','ice'].include?(type)
114
+ output*=2
115
+ end
116
+ when 'flying'
117
+ if ['electric','rock'].include?(type)
118
+ output*=0.5
119
+ elsif ['bug','fighting',"grass"].include?(type)
120
+ output*=2
121
+ end
122
+ when 'grass'
123
+ if ['bug','fire','flying','grass','poison'].include?(type)
124
+ output*=0.5
125
+ elsif ['ground','rock','water'].include?(type)
126
+ output*=2
127
+ end
128
+ when 'ghost'
129
+ if ['normal','psychic'].include?(type)
130
+ output*=0
131
+ end
132
+ when 'ground'
133
+ if ['grass'].include?(type)
134
+ output*=0.5
135
+ elsif ['electric','fire','poison','rock'].include?(type)
136
+ output*=2
137
+ elsif ['flying'].include?(type)
138
+ output*=0
139
+ end
140
+ when 'electric'
141
+ if ['electric','grass'].include?(type)
142
+ output*=0.5
143
+ elsif ['flying','water'].include?(type)
144
+ output*=2
145
+ elsif ['ground'].include?(type)
146
+ output*=0
147
+ end
148
+ when 'poison'
149
+ if ['ground','poison','rock'].include?(type)
150
+ output*=0.5
151
+ elsif ['bug','grass'].include?(type)
152
+ output*=2
153
+ end
154
+ when 'psychic'
155
+ if ['psychic'].include?(type)
156
+ output*=0.5
157
+ elsif ['fighting','poison'].include?(type)
158
+ output*=2
159
+ end
160
+ when 'rock'
161
+ if ['fighting','rock'].include?(type)
162
+ elsif ['bug','fire','flying','ice'].include?(type)
163
+ end
164
+ when 'water'
165
+ if ['grass','ice'].include?(type)
166
+ output*=0.5
167
+ elsif ['fire','ground','rock'].include?(type)
168
+ output*=2
169
+ end
170
+ else
171
+ puts "SOMETHING WENT WRONG WITH TYPE DMG"
172
+ puts "MoveType: #{move.type.downcase} Type: #{type.downcase}"
173
+ end
174
+
175
+ if(typeInput.nil? && oppPokemon.type2 !="")
176
+ output *= calcWeakResist(oppPokemon,move, oppPokemon.type2)
177
+ end
178
+ output
179
+ end
180
+
181
+ def canAttack?
182
+ #returns true if pokemon has enough PP to attack
183
+ @moves.any?{|move| move.usable?}
184
+ end
185
+
186
+ def usableMoves
187
+ #returns array of usable moves
188
+ @moves.select{|move| move.usable?}
189
+ end
190
+ end
@@ -0,0 +1,3 @@
1
+ module PoorPokemon
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "poor-pokemon/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.authors = ["Mahdi Shadkam-Farrokhi"]
8
+ spec.email = ["mahdi@allstarcode.org"]
9
+ spec.description = "A simple pokemon CLI"
10
+ spec.summary = "In this simple CLI gem game, the player selects whatever pokemon they want from their pokedex to be added to their roster of 6, and then battles against an opponent, \"Poorly Designed Boss\"."
11
+ spec.version = PoorPokemon::VERSION
12
+ spec.homepage = 'http://rubygems.org/gems/poor-pokemon'
13
+ spec.date = Time.now.utc.strftime("%Y-%m-%d")
14
+ spec.files = `git ls-files`.split($\)
15
+ spec.executables = ["poor-pokemon"]
16
+ spec.name = "poor-pokemon-cli"
17
+ spec.require_paths = ["lib", "lib/poor-pokemon"]
18
+ spec.license = "MIT"
19
+
20
+ spec.add_development_dependency "pry"
21
+
22
+ spec.add_dependency "nokogiri"
23
+ end
data/spec.md ADDED
@@ -0,0 +1,9 @@
1
+ # Specifications for the CLI Assessment
2
+
3
+ Specs:
4
+ - [x] Have a CLI for interfacing with the application
5
+ -I've created a working Ruby CLI for playing pokemon.
6
+ - [x] Pull data from an external source
7
+ -The application properly pulls data from an external website using the 'open-uri' gem.
8
+ - [x] Implement both list and detail views
9
+ -The application uses a 'pokedex' to allow users to interact with a list of pokemon (both from a full list or by searching). The users select their pokemon and store them in a roster, from which they can battle an opponent.
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poor-pokemon-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mahdi Shadkam-Farrokhi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A simple pokemon CLI
42
+ email:
43
+ - mahdi@allstarcode.org
44
+ executables:
45
+ - poor-pokemon
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitmodules"
50
+ - ".learn"
51
+ - CONTRIBUTING.md
52
+ - Gemfile
53
+ - LICENSE.md
54
+ - README.md
55
+ - bin/poor-pokemon
56
+ - config/environment.rb
57
+ - lib/poor-pokemon.rb
58
+ - lib/poor-pokemon/basePlayer.rb
59
+ - lib/poor-pokemon/cli.rb
60
+ - lib/poor-pokemon/enemy.rb
61
+ - lib/poor-pokemon/move.rb
62
+ - lib/poor-pokemon/player.rb
63
+ - lib/poor-pokemon/pokedex.rb
64
+ - lib/poor-pokemon/pokedexPokemon.rb
65
+ - lib/poor-pokemon/pokemon.rb
66
+ - lib/poor-pokemon/version.rb
67
+ - poor-pokemon-cli-gem.gemspec
68
+ - spec.md
69
+ homepage: http://rubygems.org/gems/poor-pokemon
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ - lib/poor-pokemon
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.5.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: In this simple CLI gem game, the player selects whatever pokemon they want
94
+ from their pokedex to be added to their roster of 6, and then battles against an
95
+ opponent, "Poorly Designed Boss".
96
+ test_files: []