Merge: json::serialization: fallback to the static type when there is no metadata...
[nit.git] / contrib / nitrpg / src / reactors.nit
index d1f3b3c..616bd8a 100644 (file)
 # limitations under the License.
 
 # Various implementations of `GameReactor` can be found here.
-#
-# TODO This module use a lot of magic numbers for nitcoin rewards.
-# This should be extracted from configuration or stored elsewhere.
 module reactors
 
-import game
+import events
 
 # Reacts to event that can affect players (like giving nitcoins).
 class PlayerReactor
        super GameReactor
 
-       redef fun react_event(game, e) do e.react_player_event(game)
+       # Nitcoins rewarded when the player opens a new pull request.
+       var nc_pull_open = 10
+
+       # Nitcoins rewarded when the player reviews a pull request.
+       var nc_pull_review = 2
+
+       # Nitcoins rewarded when the player has a commit merged.
+       var nc_commit_merged = 1
+
+       redef fun react_event(game, e) do e.react_player_event(self, game)
 end
 
 redef class GithubEvent
@@ -34,18 +40,53 @@ redef class GithubEvent
        #
        # Called by `PlayerReactor::react_event`.
        # No-op by default.
-       private fun react_player_event(game: Game) do end
+       private fun react_player_event(reactor: PlayerReactor, game: Game) do end
+
+       # Generates a GameEvent preinitialized for a reward event.
+       private fun player_reward_event(kind: String, player: Player, reward: Int): GameEvent do
+               var obj = new JsonObject
+               obj["player"] = player.name
+               obj["reward"] = reward
+               obj["github_event"] = self
+               var event = new GameEvent(player.game, kind, obj)
+               player.game.add_event(event)
+               return event
+       end
 end
 
 redef class PullRequestEvent
 
        # Rewards player for opened pull requests.
-       redef fun react_player_event(game) do
-               if action == "opened" then
-                       var player = pull.user.player(game)
-                       player.nitcoins += 10
-                       player.save
+       redef fun react_player_event(r, game) do
+               if action == "opened" or action == "reopened" then
+                       react_pull_open(r, game)
+               else if action == "closed" then
+                       react_pull_close(r, game)
+               end
+       end
+
+       private fun react_pull_open(r: PlayerReactor, game: Game) do
+               var player = pull.user.player(game)
+               player.nitcoins += r.nc_pull_open
+               player.save
+               var event = player_reward_event("pull_open", player, r.nc_pull_open)
+               player.add_event(event)
+       end
+
+       private fun react_pull_close(r: PlayerReactor, game: Game) do
+               var player = pull.user.player(game)
+               var reward
+               var event
+               if pull.merged then
+                       reward = pull.commits * r.nc_commit_merged
+                       event = player_reward_event("pull_merged", player, reward)
+               else
+                       reward = -r.nc_pull_open
+                       event = player_reward_event("pull_closed", player, reward)
                end
+               player.nitcoins += reward
+               player.save
+               player.add_event(event)
        end
 end
 
@@ -53,15 +94,22 @@ redef class IssueCommentEvent
 
        # Rewards player for review comments.
        #
-       # Actuallty we look if the comment contains the string `"+1"`.
-       #
        # TODO only give nitcoins if reviewers < 2
-       redef fun react_player_event(game) do
-               # FIXME use a more precise way to locate reviews
-               if comment.body.has("\\+1\\b".to_re) then
-                       var player = comment.user.player(game)
-                       player.nitcoins += 2
-                       player.save
+       # TODO give more points to first reviewer
+       redef fun react_player_event(r, game) do
+               if comment.is_ack then
+                       react_player_review(r, game)
                end
        end
+
+       # TODO same player should not be authorized to review multiple times? How to handle rerols?
+       private fun react_player_review(r: PlayerReactor, game: Game) do
+               if issue.state == "closed" then return
+               var player = comment.user.player(game)
+               if issue.user == player.user then return
+               player.nitcoins += r.nc_pull_review
+               player.save
+               var event = player_reward_event("pull_review", player, r.nc_pull_review)
+               player.add_event(event)
+       end
 end