hlockey 5 → 6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/data/election.json +20 -0
  3. data/data/information.json +5 -0
  4. data/data/league.json +1984 -0
  5. data/data/links.json +5 -0
  6. data/data/previous_election_results.json +98 -0
  7. data/lib/hlockey/actions.rb +22 -0
  8. data/lib/hlockey/data.rb +6 -5
  9. data/lib/hlockey/game/fight.rb +28 -17
  10. data/lib/hlockey/game/weather/audacity.rb +1 -1
  11. data/lib/hlockey/game/weather/chicken.rb +1 -1
  12. data/lib/hlockey/game/weather/sunset.rb +1 -1
  13. data/lib/hlockey/game/weather/waves.rb +11 -5
  14. data/lib/hlockey/game/weather/weatherable.rb +8 -8
  15. data/lib/hlockey/game.rb +58 -33
  16. data/lib/hlockey/league.rb +60 -63
  17. data/lib/hlockey/message.rb +54 -56
  18. data/lib/hlockey/mod/fencebuilder.rb +16 -0
  19. data/lib/hlockey/mod/fencedestroyer.rb +16 -0
  20. data/lib/hlockey/mod/handholding.rb +55 -0
  21. data/lib/hlockey/mod/immaterial.rb +26 -0
  22. data/lib/hlockey/mod/locked.rb +22 -0
  23. data/lib/hlockey/mod/moddable.rb +49 -0
  24. data/lib/hlockey/mod/nonconfrontational.rb +17 -0
  25. data/lib/hlockey/mod/powernapper.rb +46 -0
  26. data/lib/hlockey/mod/punchy.rb +17 -0
  27. data/lib/hlockey/mod.rb +25 -0
  28. data/lib/hlockey/selfdescribable.rb +9 -0
  29. data/lib/hlockey/team/player.rb +37 -58
  30. data/lib/hlockey/team/stadium.rb +10 -7
  31. data/lib/hlockey/team.rb +56 -41
  32. data/lib/hlockey/version.rb +1 -1
  33. metadata +27 -17
  34. data/data/election.yaml +0 -21
  35. data/data/external/names.txt +0 -19948
  36. data/data/information.yaml +0 -24
  37. data/data/league.yaml +0 -1694
  38. data/data/links.yaml +0 -3
  39. data/data/previous_election_results.yaml +0 -65
  40. data/lib/hlockey/game/actions.rb +0 -24
data/data/links.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "Website": "https://hlockey.gay",
3
+ "Source Code": "https://codeberg.org/LavenderPerry/hlockey",
4
+ "Discord": "https://discord.gg/2N8VN8Q69E"
5
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "vote_amt": 159,
3
+ "categories": {
4
+ "Bribery (49 votes)": {
5
+ "Winning bribe": {
6
+ "winner": "Mods Help (23 votes)"
7
+ }
8
+ },
9
+ "Treasure (83 votes)": {
10
+ "Dave": {
11
+ "winner": "Pica Acid (2 votes / 21 total)",
12
+ "most_votes": "Sydney Thinkers (6 votes)"
13
+ },
14
+ "Nice": {
15
+ "winner": "Nice Backflippers (2 votes / 15 total)",
16
+ "most_votes": "Dawson City Impostors (7 votes)"
17
+ },
18
+ "Vengabus": {
19
+ "winner": "Antalya Pirates (2 votes / 22 total)",
20
+ "most_votes": "Stony Brook Reapers (11 votes)"
21
+ },
22
+ "Unvengabus": {
23
+ "winner": "Rio de Janeiro Directors (Dry Warm) (0 votes / 0 total)"
24
+ },
25
+ "Shared Training": {
26
+ "winner": "Pompei Eruptions (Dry Warm) (4 votes / 16 total)"
27
+ },
28
+ "Theft": {
29
+ "winner": "Sydney Thinkers (8 votes / 9 total)"
30
+ },
31
+ "Hidden Treasure - Evolve": {
32
+ "winner": "Baden Hallucinations (0 votes / 0 total)"
33
+ }
34
+ },
35
+ "Coaching (27 votes)": {
36
+ "Antalya Pirates": {
37
+ "winner": "Draft (1 vote / 1 total)"
38
+ },
39
+ "Baden Hallucinations": {
40
+ "winner": "Draft (0 votes / 0 total)"
41
+ },
42
+ "Kópavogur Seals": {
43
+ "winner": "Big Gamble (0 votes / 0 total)"
44
+ },
45
+ "Lagos Soup": {
46
+ "winner": "Small Gamble (0 votes / 0 total)"
47
+ },
48
+ "Pica Acid": {
49
+ "winner": "Please Block Shots (2 votes / 2 total)"
50
+ },
51
+ "Dawson City Impostors": {
52
+ "winner": "Draft (4 votes / 4 total)"
53
+ },
54
+ "Erlangen Ohms": {
55
+ "winner": "Please Win Faceoffs (1 vote / 2 total)"
56
+ },
57
+ "Pompei Eruptions": {
58
+ "winner": "Please Win Faceoffs (0 votes / 0 total)"
59
+ },
60
+ "Rio de Janeiro Directors": {
61
+ "winner": "Please Win Faceoffs (1 vote / 1 total)"
62
+ },
63
+ "Wyrzysk Rockets": {
64
+ "winner": "Big Gamble (0 votes / 0 total)"
65
+ },
66
+ "Cape Town Transplants": {
67
+ "winner": "Draft (1 vote / 2 total)"
68
+ },
69
+ "Manbij Fish": {
70
+ "winner": "Draft (1 vote / 1 total)"
71
+ },
72
+ "Nagqu Paint": {
73
+ "winner": "Draft (1 vote / 1 total)"
74
+ },
75
+ "Nice Backflippers": {
76
+ "winner": "Draft (1 vote / 1 total)"
77
+ },
78
+ "Orcadas Base Fog": {
79
+ "winner": "Draft (2 votes / 2 total)"
80
+ },
81
+ "Baghdad Abacuses": {
82
+ "winner": "Clock Unwise (0 votes / 0 total)"
83
+ },
84
+ "Jakarta Architects": {
85
+ "winner": "Clock Wise (0 votes / 0 total)"
86
+ },
87
+ "Kyoto Payphones": {
88
+ "winner": "Small Gamble (1 vote / 2 total)"
89
+ },
90
+ "Stony Brook Reapers": {
91
+ "winner": "Please Win Faceoffs (1 vote / 1 total)"
92
+ },
93
+ "Sydney Thinkers": {
94
+ "winner": "Clock Wise (7 votes / 7 total)"
95
+ }
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,22 @@
1
+ require("hlockey/constants")
2
+
3
+ module Hlockey
4
+ ##
5
+ # For classes that deal with actions within a Hlockey game.
6
+ module Actions
7
+ private
8
+
9
+ # For an event that should happen randomly about a certain amount of times per game,
10
+ # returns if the event should happen or not. Should be called once per action.
11
+ # @param times [Integer] the approximate amount of times the event should occur
12
+ # @return [Boolean] if the event should occur
13
+ def random_event_occurs?(times = 1, prng: @prng) =
14
+ prng.rand(NON_OT_ACTIONS / times).zero?
15
+
16
+ # @param succeed_boost [Numeric] increases chance of action succeeding
17
+ # @param fail_boost [Numeric] decreases chance of action succeeding
18
+ # @return [Boolean] if the action succeeded
19
+ def action_succeeds?(succeed_boost, fail_boost, prng: @prng) =
20
+ prng.rand(20) + (succeed_boost - fail_boost) > 9
21
+ end
22
+ end
data/lib/hlockey/data.rb CHANGED
@@ -1,5 +1,4 @@
1
- require("hlockey/team") # Classes stored in league data
2
- require("yaml")
1
+ require("json")
3
2
 
4
3
  module Hlockey
5
4
  ##
@@ -8,9 +7,11 @@ module Hlockey
8
7
  class << self
9
8
  data_dir = File.expand_path("../../data", __dir__)
10
9
 
11
- Dir.glob("*.yaml", base: data_dir).each do |data_file|
12
- category = File.basename(data_file, ".yaml")
13
- define_method(category) { YAML.unsafe_load_file("#{data_dir}/#{data_file}") }
10
+ Dir.glob("*.json", base: data_dir).each do |data_file|
11
+ # @return [Hash] loaded data
12
+ define_method(File.basename(data_file, ".json")) do
13
+ JSON.parse(File.read("#{data_dir}/#{data_file}"), symbolize_names: true)
14
+ end
14
15
  end
15
16
  end
16
17
  end
@@ -1,4 +1,4 @@
1
- require("hlockey/game/actions")
1
+ require("hlockey/actions")
2
2
  require("hlockey/message")
3
3
 
4
4
  module Hlockey
@@ -15,15 +15,21 @@ module Hlockey
15
15
  attr_reader(:score)
16
16
 
17
17
  # @param game [Game] the game the fight is a part of
18
- def initialize(game)
18
+ def initialize(game, starting_player = nil)
19
19
  @home = game.home
20
20
  @away = game.away
21
21
  @prng = game.prng
22
22
  @actions = 0
23
- @players = {
24
- home: [@home.roster.values.sample(random: @prng)],
25
- away: [@away.roster.values.sample(random: @prng)]
26
- }
23
+ @players = { home: [], away: [] }
24
+ @players.each_key do |team|
25
+ add_player(if send(team).roster.value?(starting_player)
26
+ starting_player
27
+ else
28
+ get_joining_player(team)
29
+ end,
30
+ team)
31
+ end
32
+
27
33
  @score = { home: 0, away: 0 }
28
34
  end
29
35
 
@@ -44,9 +50,7 @@ module Hlockey
44
50
  return attack if player_joining.nil?
45
51
  end
46
52
 
47
- @players[team_joining] << player_joining
48
-
49
- Message.PlayerJoinedFight(send(team_joining), player_joining)
53
+ add_player(player_joining, team_joining)
50
54
  else # fight ends
51
55
  Message.FightEnded
52
56
  end
@@ -75,21 +79,28 @@ module Hlockey
75
79
  end
76
80
 
77
81
  # @param team [:home, :away]
78
- # @return [Player, nil]
79
- def get_joining_player(team)
82
+ # @return [Team::Player, nil]
83
+ def get_joining_player(team) =
80
84
  (send(team).roster.values - @players[team]).sample(random: @prng)
85
+
86
+ # @param player [Team::Player]
87
+ # @param team [:home, :away]
88
+ # @return [Message] the join message
89
+ def add_player(player, team)
90
+ mods_res = player.mods_do(:on_join_fight)
91
+ player = mods_res if mods_res
92
+
93
+ @players[team] << player
94
+
95
+ Message.PlayerJoinedFight(player)
81
96
  end
82
97
 
83
98
  # @return [:home, :away] randomly selected based on amount of players in fight
84
- def rand_team
85
- rand_is_home? ? :home : :away
86
- end
99
+ def rand_team = rand_is_home? ? :home : :away
87
100
 
88
101
  # @param team [:home, :away]
89
102
  # @return [:home, :away] :away if `team` is :home, :home if `team` is :away
90
- def opposite(team)
91
- team == :home ? :away : :home
92
- end
103
+ def opposite(team) = team == :home ? :away : :home
93
104
 
94
105
  # @return [Boolean] if randomly selected team is home team
95
106
  def rand_is_home?
@@ -1,5 +1,5 @@
1
1
  require("hlockey/game/weather/weatherable")
2
- require("hlockey/game/actions")
2
+ require("hlockey/actions")
3
3
 
4
4
  module Hlockey
5
5
  class Game
@@ -1,5 +1,5 @@
1
1
  require("hlockey/game/weather/weatherable")
2
- require("hlockey/game/actions")
2
+ require("hlockey/actions")
3
3
  require("hlockey/message")
4
4
 
5
5
  module Hlockey
@@ -15,7 +15,7 @@ module Hlockey
15
15
 
16
16
  def on_goal(scoring_team)
17
17
  @score_amt[scoring_team] += 1
18
- @game.score[scoring_team] -= @score_amt[scoring_team] * 0.2
18
+ @game.score[scoring_team] -= @score_amt[scoring_team] * 0.3
19
19
  end
20
20
  end
21
21
  end
@@ -1,5 +1,5 @@
1
1
  require("hlockey/game/weather/weatherable")
2
- require("hlockey/game/actions")
2
+ require("hlockey/actions")
3
3
  require("hlockey/message")
4
4
 
5
5
  module Hlockey
@@ -7,7 +7,7 @@ module Hlockey
7
7
  module Weather
8
8
  ##
9
9
  # Waves weather
10
- # Swaps the worst roster player with a random shadow player permanently
10
+ # Swaps a roster player (worst most likely) with a random shadow player permanently
11
11
  class Waves
12
12
  include(Weatherable)
13
13
  include(Actions)
@@ -17,9 +17,15 @@ module Hlockey
17
17
 
18
18
  team_sym = rand_team
19
19
  team = @game.send(team_sym)
20
- @game.stream << Message.WavesWashedAway(*swap(team_sym,
21
- team.worst_player_pos,
22
- @prng.rand(team.shadows.length)))
20
+ @game.stream << Message.WavesWashedAway(
21
+ *swap(team_sym,
22
+ if @prng.rand(5).zero?
23
+ team.roster.keys.sample(random: @prng)
24
+ else
25
+ team.worst_player_pos
26
+ end,
27
+ @prng.rand(team.shadows.length))
28
+ )
23
29
  end
24
30
  end
25
31
  end
@@ -1,4 +1,5 @@
1
1
  require("hlockey/constants")
2
+ require("hlockey/selfdescribable")
2
3
 
3
4
  module Hlockey
4
5
  class Game
@@ -7,6 +8,8 @@ module Hlockey
7
8
  # Module with needed methods for weathers, that every weather includes
8
9
  # All methods starting with "on" represent game events weathers may respond to
9
10
  module Weatherable
11
+ include(SelfDescribable)
12
+
10
13
  def initialize(game)
11
14
  @game = game
12
15
  @home = @game.home
@@ -14,10 +17,6 @@ module Hlockey
14
17
  @prng = @game.prng
15
18
  end
16
19
 
17
- def to_s
18
- self.class.to_s.split("::").last
19
- end
20
-
21
20
  def on_game_start() end
22
21
 
23
22
  def on_game_end() end
@@ -34,7 +33,7 @@ module Hlockey
34
33
  # @param team_sym [:home, :away]
35
34
  # @param pos [Symbol] position of roster player swapped out
36
35
  # @param shadows_idx [Integer] index of shadows player swapped in
37
- # @return [Array<Player>] the players that were swapped
36
+ # @return [Array<Team::Player>] the players that were swapped
38
37
  def swap(team_sym, pos, shadows_idx)
39
38
  team = @game.send(team_sym)
40
39
 
@@ -50,13 +49,14 @@ module Hlockey
50
49
  player_array[player_idx] = next_player unless player_idx.nil?
51
50
  end
52
51
 
52
+ prev_player.mods_do(:on_swap, false, shadows_idx, pos, @prng)
53
+ next_player.mods_do(:on_swap, true, pos, shadows_idx, @prng)
54
+
53
55
  [prev_player, next_player]
54
56
  end
55
57
 
56
58
  # @return [:home, :away]
57
- def rand_team
58
- @prng.rand(2).zero? ? :home : :away
59
- end
59
+ def rand_team = @prng.rand(2).zero? ? :home : :away
60
60
  end
61
61
  end
62
62
  end
data/lib/hlockey/game.rb CHANGED
@@ -1,6 +1,6 @@
1
- require("hlockey/game/actions")
2
1
  require("hlockey/game/fight")
3
2
  require("hlockey/game/weather")
3
+ require("hlockey/actions")
4
4
  require("hlockey/constants")
5
5
  require("hlockey/message")
6
6
  require("hlockey/utils")
@@ -17,6 +17,9 @@ module Hlockey
17
17
  # @return [Random] should be the same as the league's
18
18
  attr_reader(:prng)
19
19
 
20
+ # @return [Hash<Symbol => Integer>] the score of each team
21
+ attr_reader(:score)
22
+
20
23
  # @return [Team::Stadium] the stadium this game is located at
21
24
  attr_reader(:stadium)
22
25
 
@@ -26,9 +29,6 @@ module Hlockey
26
29
  # @return [Array<Message>] messages about game events
27
30
  attr_reader(:stream)
28
31
 
29
- # @return [Hash<Symbol => Integer>] the score of each team
30
- attr_reader(:score)
31
-
32
32
  # @return [Boolean] if the game is still in progress
33
33
  attr_reader(:in_progress)
34
34
 
@@ -38,20 +38,29 @@ module Hlockey
38
38
  # @return [Fight, nil] the current fight, if there is any
39
39
  attr_reader(:fight)
40
40
 
41
+ # @return [Hash<Player => Hash<Symbol => Number>>] stats of players before changes
42
+ attr_reader(:pre_tmp_change_stats)
43
+
44
+ alias in_progress? in_progress
45
+
41
46
  # @param home [Team]
42
47
  # @param away [Team]
43
48
  # @param prng [Random] should be League#prng
44
- def initialize(home, away, prng)
49
+ # @param weather [Class<Weatherable>]
50
+ def initialize(home, away, prng, weather = nil)
45
51
  @home = home
46
52
  @away = away
47
53
  @prng = prng
54
+
48
55
  @stadium = @home.stadium
49
- @weather = Weather::WEATHERS.sample(random: prng).new(self)
50
- @stream = [Message.StartOfGame]
56
+
57
+ weather ||= Weather::WEATHERS.sample(random: prng)
58
+ @weather = weather.new(self)
51
59
  @score = { home: 0, away: 0 }
52
60
  @in_progress = true
53
61
  @actions = 0
54
62
  @period = 1
63
+ @stream = [Message.StartOfGame]
55
64
  @faceoff = true
56
65
  @faceoff_won = false
57
66
  @team_with_puck = nil
@@ -60,16 +69,26 @@ module Hlockey
60
69
  @shooting_chance = 0
61
70
  @fight = nil
62
71
  @fight_chance = 0
63
- @pre_morale_change_stats = {}
64
- @partying_teams = [@home, @away].select { |t| t.status == :partying }
72
+ @pre_tmp_change_stats = {}
73
+ @partying_teams = [@home, @away].select { _1.status == :partying }
65
74
 
66
75
  @weather.on_game_start
67
76
  end
68
77
 
78
+ # @return [Hash]
79
+ def to_h = {
80
+ home: @home.name,
81
+ away: @away.name,
82
+ stadium: @stadium.to_s,
83
+ weather: @weather.to_s,
84
+ score: @score,
85
+ in_progress?: @in_progress,
86
+ period: @period,
87
+ stream: @stream.map { _1.to_s(do_color: false) }
88
+ }
89
+
69
90
  # @return [String]
70
- def to_s
71
- "#{Message.color(@home)} vs #{Message.color(@away)}"
72
- end
91
+ def to_s = "#{Message.color(@home)} vs #{Message.color(@away)}"
73
92
 
74
93
  # Update the game state by one action
75
94
  def update
@@ -79,6 +98,14 @@ module Hlockey
79
98
  handle_parties
80
99
  end
81
100
 
101
+ # Starts a fight in the game
102
+ # @param starting_player [Player, nil] the player that started the fight (optional)
103
+ def start_fight(starting_player = nil)
104
+ @fight = Fight.new(self, starting_player)
105
+ @stream << Message.FightStarted(@fight.players[:home].first,
106
+ @fight.players[:away].first)
107
+ end
108
+
82
109
  private
83
110
 
84
111
  # Does an action in the game
@@ -87,6 +114,7 @@ module Hlockey
87
114
  @actions += 1
88
115
 
89
116
  @weather.on_action
117
+ (@home.roster.values + @away.roster.values).each { _1.mods_do(:on_action, self) }
90
118
 
91
119
  unless @fight.nil?
92
120
  fight_message = @fight.next_action
@@ -129,9 +157,9 @@ module Hlockey
129
157
  stat = player.stats.keys.sample(random: @prng)
130
158
  player.stats[stat] += 0.1
131
159
  @stream << Message.Partying(player)
132
- next if @pre_morale_change_stats[player].nil?
160
+ next if @pre_tmp_change_stats[player].nil?
133
161
 
134
- @pre_morale_change_stats[player][stat] += 0.1
162
+ @pre_tmp_change_stats[player][stat] += 0.1
135
163
  end
136
164
  end
137
165
 
@@ -159,9 +187,15 @@ module Hlockey
159
187
  def check
160
188
  defender_pos = defensive_pos
161
189
  defender = @puckless_team.roster[defender_pos]
162
- @stream << Message.Hit(puck_holder, defender,
163
- try_take_puck(defender_pos), @team_with_puck,
190
+
191
+ mods_messages = puck_holder.mods.map { _1.on_got_hit(self, defender) }.compact
192
+
193
+ @stream << Message.Hit(puck_holder,
194
+ defender,
195
+ mods_messages.empty? && try_take_puck(defender_pos),
196
+ @team_with_puck,
164
197
  @shooting_chance)
198
+ @stream.concat(mods_messages)
165
199
  @fight_chance += 0.1
166
200
  end
167
201
 
@@ -172,10 +206,10 @@ module Hlockey
172
206
  return if @puck_holder_pos.nil?
173
207
 
174
208
  if @shooting_chance < 5 &&
175
- try_block_shot(@prng.rand(2).zero? ? :ldef : :rdef, audacity: audacity)
209
+ try_block_shot(@prng.rand(2).zero? ? :ldef : :rdef, audacity:)
176
210
  return
177
211
  end
178
- return if try_block_shot(:goalie, audacity: audacity)
212
+ return if try_block_shot(:goalie, audacity:)
179
213
 
180
214
  # Goal scored
181
215
 
@@ -201,7 +235,7 @@ module Hlockey
201
235
  if @period > NON_OT_PERIODS &&
202
236
  !(@score[:home] == @score[:away] && @period <= TOTAL_PERIODS)
203
237
  # Game is over
204
- @pre_morale_change_stats.each { |player, stats| player.stats = stats }
238
+ @pre_tmp_change_stats.each { |player, stats| player.stats = stats }
205
239
  @weather.on_game_end
206
240
  @in_progress = false
207
241
  winner, loser = @score[:away] > @score[:home] ? [@away, @home] : [@home, @away]
@@ -279,20 +313,15 @@ module Hlockey
279
313
  true
280
314
  end
281
315
 
282
- def start_fight
283
- @fight = Fight.new(self)
284
- @stream << Message.FightStarted(@fight.players[:home].first,
285
- @fight.players[:away].first)
286
- end
287
-
316
+ # Add amount to each stat of each player of team until the end of the game
288
317
  # @param team [Team]
289
318
  # @param amount [Numeric]
290
319
  def change_morale(team, amount)
291
320
  return if amount.zero?
292
321
 
293
322
  team.roster.each_value do |player|
294
- if @pre_morale_change_stats[player].nil?
295
- @pre_morale_change_stats[player] = player.stats.clone
323
+ if @pre_tmp_change_stats[player].nil?
324
+ @pre_tmp_change_stats[player] = player.stats.clone
296
325
  end
297
326
 
298
327
  player.stats.transform_values! { |stat| stat + amount }
@@ -302,9 +331,7 @@ module Hlockey
302
331
  end
303
332
 
304
333
  # @return [Player]
305
- def puck_holder
306
- @team_with_puck.roster[@puck_holder_pos]
307
- end
334
+ def puck_holder = @team_with_puck.roster[@puck_holder_pos]
308
335
 
309
336
  # @return [Symbol]
310
337
  def pass_reciever
@@ -314,9 +341,7 @@ module Hlockey
314
341
  end
315
342
 
316
343
  # @return [Symbol]
317
- def defensive_pos
318
- Utils.weighted_random(weights(@shooting_chance < 3), @prng)
319
- end
344
+ def defensive_pos = Utils.weighted_random(weights(@shooting_chance < 3), @prng)
320
345
 
321
346
  # @return [Hash<Symbol => Integer>]
322
347
  def weights(offensive)