hlockey 5 → 6

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