{"action":"opened","number":1628,"pull_request":{"url":"https://api.github.com/repos/otland/forgottenserver/pulls/1628","id":52636193,"html_url":"https://github.com/otland/forgottenserver/pull/1628","diff_url":"https://github.com/otland/forgottenserver/pull/1628.diff","patch_url":"https://github.com/otland/forgottenserver/pull/1628.patch","issue_url":"https://api.github.com/repos/otland/forgottenserver/issues/1628","number":1628,"state":"open","locked":false,"title":"Reward Boss implementation faithful to Tibia's one.","user":{"login":"socket2810","id":7633179,"avatar_url":"https://avatars.githubusercontent.com/u/7633179?v=3","gravatar_id":"","url":"https://api.github.com/users/socket2810","html_url":"https://github.com/socket2810","followers_url":"https://api.github.com/users/socket2810/followers","following_url":"https://api.github.com/users/socket2810/following{/other_user}","gists_url":"https://api.github.com/users/socket2810/gists{/gist_id}","starred_url":"https://api.github.com/users/socket2810/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/socket2810/subscriptions","organizations_url":"https://api.github.com/users/socket2810/orgs","repos_url":"https://api.github.com/users/socket2810/repos","events_url":"https://api.github.com/users/socket2810/events{/privacy}","received_events_url":"https://api.github.com/users/socket2810/received_events","type":"User","site_admin":false},"body":"## Reasoning\r\nAfter seeing a few reward systems on [OTLand](https://otland.net/) try and fail to replicate the original one, I decided to give it a try myself. Some images of the result:\r\n![Boss Loot](http://i.imgur.com/1QtRIGX.png) ![Reward Chest](http://i.imgur.com/bB4a2I3.png)       ![Reward Chest 2](http://i.imgur.com/N5GCeGN.png)\r\n\r\n## How I did it\r\n### Boss Corpses\r\nThe difference between a normal monster corpse and a corpse that should yield individual rewards to players that participated in the fight is its attributes. **ITEM_ATTRIBUTE_CORPSEOWNER** is set to 2^31-1 and **ITEM_ATTRIBUTE_DATE** stores the time it was killed. \r\n### New class: Reward\r\nIt's the *Reward* class responsibility to store the different rewards a player may receive and, just like a depot chest, its contents are stored into the database when the player logs out and again loaded when they log back.\r\n### New class: Reward Chest\r\nAnalogous to the Depot Locker, the *Reward Chest* contains the *Reward* (that inside the game is a [reward container](http://tibia.wikia.com/wiki/Reward_Container). However, it contains all the *Rewards*. They are inserted into the chest during the player load phase and every time another *Reward* is created via:\r\n````\r\nPlayer::getReward(uint32_t timestamp, bool autoCreate);\r\n// or\r\nPlayer.getReward(self, timestamp, autoCreate)\r\n````\r\n\r\n## Specifics\r\n### Timestamps\r\nTimestamps are set both on the boss corpse and on the in-game *reward container* / *Reward* object. They're used to identify the *Reward* and to limit how long the reward is stored in the database (Tibia chose a maximum of 7 days).\r\n### How is each player attributed a different corpse?\r\nThe *Player* class now holds a *rewardCorpses* map that stores each corpse, which are instantiated the first time that the player opens the body and are collected in the player destructor (together with the player's *Rewards*).\r\n### How is the loot handled?\r\nEach player's contribution is measured by an *onHealthChange* event. The player will be considered **active** in the fight if he is currently in the boss' **targetList** - or whenever he heals someone that is currently active. The contribution is kept stored even if the player disconnects during the fight. If during the loot distribution phase the player is offline, he'll still receive his reward (Lua implementation: [insertRewardBag(guid, timestamp, itemList)](https://github.com/socket2810/forgottenserver/blob/master/data/creaturescripts/scripts/boss.lua#L188)).\r\n### How to enable reward distribution to a boss\r\nSet the **rewardboss* flag to true on the monster .xml file:\r\n````xml\r\n<flag rewardboss=\"1\" />\r\n````\r\nAnd register the corresponding events by calling *Monster.setReward(self, enable)* whenever a boss is summoned (e.g [place_monster.lua](https://github.com/socket2810/forgottenserver/blob/master/data/talkactions/scripts/place_monster.lua#L14)).\r\n### Player contribution\r\nPlayer contribution is currently calculated like this:\r\n````lua\r\nlocal score = (playerDamageOut / totalDamageOut) + (playerDamageIn / totalDamageIn) + (player.Healing / totalHealing)\r\nscore = score / 3 -- normalize to 0-1\r\nlocal expectedScore = 1 / participants\r\nlocal lootFactor = 1\r\nlootFactor = lootFactor / participants ^ (1 / 3) -- tone down the loot a notch if there are many participants\r\nlootFactor = lootFactor * (1 + lootFactor) ^ (score / expectedScore) -- increase the loot multiplicatively by how many times the player surpassed the expected score\r\n````\r\nEach *lootBlock* is therefore **lootFactor** times more probable to be awarded to a specific player. However it is far from being optimal if we want to achieve a result similar to Tibia's and *only* with the community help we will manage that.\r\n","created_at":"2015-12-04T06:59:26Z","updated_at":"2015-12-04T06:59:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/otland/forgottenserver/pulls/1628/commits","review_comments_url":"https://api.github.com/repos/otland/forgottenserver/pulls/1628/comments","review_comment_url":"https://api.github.com/repos/otland/forgottenserver/pulls/comments{/number}","comments_url":"https://api.github.com/repos/otland/forgottenserver/issues/1628/comments","statuses_url":"https://api.github.com/repos/otland/forgottenserver/statuses/25a52dc06ef5c633e79a34eabebbb099c1084f68","head":{"label":"socket2810:master","ref":"master","sha":"25a52dc06ef5c633e79a34eabebbb099c1084f68","user":{"login":"socket2810","id":7633179,"avatar_url":"https://avatars.githubusercontent.com/u/7633179?v=3","gravatar_id":"","url":"https://api.github.com/users/socket2810","html_url":"https://github.com/socket2810","followers_url":"https://api.github.com/users/socket2810/followers","following_url":"https://api.github.com/users/socket2810/following{/other_user}","gists_url":"https://api.github.com/users/socket2810/gists{/gist_id}","starred_url":"https://api.github.com/users/socket2810/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/socket2810/subscriptions","organizations_url":"https://api.github.com/users/socket2810/orgs","repos_url":"https://api.github.com/users/socket2810/repos","events_url":"https://api.github.com/users/socket2810/events{/privacy}","received_events_url":"https://api.github.com/users/socket2810/received_events","type":"User","site_admin":false},"repo":{"id":47339834,"name":"forgottenserver","full_name":"socket2810/forgottenserver","owner":{"login":"socket2810","id":7633179,"avatar_url":"https://avatars.githubusercontent.com/u/7633179?v=3","gravatar_id":"","url":"https://api.github.com/users/socket2810","html_url":"https://github.com/socket2810","followers_url":"https://api.github.com/users/socket2810/followers","following_url":"https://api.github.com/users/socket2810/following{/other_user}","gists_url":"https://api.github.com/users/socket2810/gists{/gist_id}","starred_url":"https://api.github.com/users/socket2810/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/socket2810/subscriptions","organizations_url":"https://api.github.com/users/socket2810/orgs","repos_url":"https://api.github.com/users/socket2810/repos","events_url":"https://api.github.com/users/socket2810/events{/privacy}","received_events_url":"https://api.github.com/users/socket2810/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/socket2810/forgottenserver","description":"A free and open-source MMORPG server emulator written in C++","fork":true,"url":"https://api.github.com/repos/socket2810/forgottenserver","forks_url":"https://api.github.com/repos/socket2810/forgottenserver/forks","keys_url":"https://api.github.com/repos/socket2810/forgottenserver/keys{/key_id}","collaborators_url":"https://api.github.com/repos/socket2810/forgottenserver/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/socket2810/forgottenserver/teams","hooks_url":"https://api.github.com/repos/socket2810/forgottenserver/hooks","issue_events_url":"https://api.github.com/repos/socket2810/forgottenserver/issues/events{/number}","events_url":"https://api.github.com/repos/socket2810/forgottenserver/events","assignees_url":"https://api.github.com/repos/socket2810/forgottenserver/assignees{/user}","branches_url":"https://api.github.com/repos/socket2810/forgottenserver/branches{/branch}","tags_url":"https://api.github.com/repos/socket2810/forgottenserver/tags","blobs_url":"https://api.github.com/repos/socket2810/forgottenserver/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/socket2810/forgottenserver/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/socket2810/forgottenserver/git/refs{/sha}","trees_url":"https://api.github.com/repos/socket2810/forgottenserver/git/trees{/sha}","statuses_url":"https://api.github.com/repos/socket2810/forgottenserver/statuses/{sha}","languages_url":"https://api.github.com/repos/socket2810/forgottenserver/languages","stargazers_url":"https://api.github.com/repos/socket2810/forgottenserver/stargazers","contributors_url":"https://api.github.com/repos/socket2810/forgottenserver/contributors","subscribers_url":"https://api.github.com/repos/socket2810/forgottenserver/subscribers","subscription_url":"https://api.github.com/repos/socket2810/forgottenserver/subscription","commits_url":"https://api.github.com/repos/socket2810/forgottenserver/commits{/sha}","git_commits_url":"https://api.github.com/repos/socket2810/forgottenserver/git/commits{/sha}","comments_url":"https://api.github.com/repos/socket2810/forgottenserver/comments{/number}","issue_comment_url":"https://api.github.com/repos/socket2810/forgottenserver/issues/comments{/number}","contents_url":"https://api.github.com/repos/socket2810/forgottenserver/contents/{+path}","compare_url":"https://api.github.com/repos/socket2810/forgottenserver/compare/{base}...{head}","merges_url":"https://api.github.com/repos/socket2810/forgottenserver/merges","archive_url":"https://api.github.com/repos/socket2810/forgottenserver/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/socket2810/forgottenserver/downloads","issues_url":"https://api.github.com/repos/socket2810/forgottenserver/issues{/number}","pulls_url":"https://api.github.com/repos/socket2810/forgottenserver/pulls{/number}","milestones_url":"https://api.github.com/repos/socket2810/forgottenserver/milestones{/number}","notifications_url":"https://api.github.com/repos/socket2810/forgottenserver/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/socket2810/forgottenserver/labels{/name}","releases_url":"https://api.github.com/repos/socket2810/forgottenserver/releases{/id}","created_at":"2015-12-03T15:14:41Z","updated_at":"2015-12-03T15:14:45Z","pushed_at":"2015-12-04T05:49:18Z","git_url":"git://github.com/socket2810/forgottenserver.git","ssh_url":"git@github.com:socket2810/forgottenserver.git","clone_url":"https://github.com/socket2810/forgottenserver.git","svn_url":"https://github.com/socket2810/forgottenserver","homepage":"","size":12121,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"otland:master","ref":"master","sha":"192a8ca2dfa0cf13d4163a9496edafef3e96a507","user":{"login":"otland","id":4956302,"avatar_url":"https://avatars.githubusercontent.com/u/4956302?v=3","gravatar_id":"","url":"https://api.github.com/users/otland","html_url":"https://github.com/otland","followers_url":"https://api.github.com/users/otland/followers","following_url":"https://api.github.com/users/otland/following{/other_user}","gists_url":"https://api.github.com/users/otland/gists{/gist_id}","starred_url":"https://api.github.com/users/otland/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/otland/subscriptions","organizations_url":"https://api.github.com/users/otland/orgs","repos_url":"https://api.github.com/users/otland/repos","events_url":"https://api.github.com/users/otland/events{/privacy}","received_events_url":"https://api.github.com/users/otland/received_events","type":"Organization","site_admin":false},"repo":{"id":11081909,"name":"forgottenserver","full_name":"otland/forgottenserver","owner":{"login":"otland","id":4956302,"avatar_url":"https://avatars.githubusercontent.com/u/4956302?v=3","gravatar_id":"","url":"https://api.github.com/users/otland","html_url":"https://github.com/otland","followers_url":"https://api.github.com/users/otland/followers","following_url":"https://api.github.com/users/otland/following{/other_user}","gists_url":"https://api.github.com/users/otland/gists{/gist_id}","starred_url":"https://api.github.com/users/otland/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/otland/subscriptions","organizations_url":"https://api.github.com/users/otland/orgs","repos_url":"https://api.github.com/users/otland/repos","events_url":"https://api.github.com/users/otland/events{/privacy}","received_events_url":"https://api.github.com/users/otland/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/otland/forgottenserver","description":"A free and open-source MMORPG server emulator written in C++","fork":false,"url":"https://api.github.com/repos/otland/forgottenserver","forks_url":"https://api.github.com/repos/otland/forgottenserver/forks","keys_url":"https://api.github.com/repos/otland/forgottenserver/keys{/key_id}","collaborators_url":"https://api.github.com/repos/otland/forgottenserver/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/otland/forgottenserver/teams","hooks_url":"https://api.github.com/repos/otland/forgottenserver/hooks","issue_events_url":"https://api.github.com/repos/otland/forgottenserver/issues/events{/number}","events_url":"https://api.github.com/repos/otland/forgottenserver/events","assignees_url":"https://api.github.com/repos/otland/forgottenserver/assignees{/user}","branches_url":"https://api.github.com/repos/otland/forgottenserver/branches{/branch}","tags_url":"https://api.github.com/repos/otland/forgottenserver/tags","blobs_url":"https://api.github.com/repos/otland/forgottenserver/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/otland/forgottenserver/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/otland/forgottenserver/git/refs{/sha}","trees_url":"https://api.github.com/repos/otland/forgottenserver/git/trees{/sha}","statuses_url":"https://api.github.com/repos/otland/forgottenserver/statuses/{sha}","languages_url":"https://api.github.com/repos/otland/forgottenserver/languages","stargazers_url":"https://api.github.com/repos/otland/forgottenserver/stargazers","contributors_url":"https://api.github.com/repos/otland/forgottenserver/contributors","subscribers_url":"https://api.github.com/repos/otland/forgottenserver/subscribers","subscription_url":"https://api.github.com/repos/otland/forgottenserver/subscription","commits_url":"https://api.github.com/repos/otland/forgottenserver/commits{/sha}","git_commits_url":"https://api.github.com/repos/otland/forgottenserver/git/commits{/sha}","comments_url":"https://api.github.com/repos/otland/forgottenserver/comments{/number}","issue_comment_url":"https://api.github.com/repos/otland/forgottenserver/issues/comments{/number}","contents_url":"https://api.github.com/repos/otland/forgottenserver/contents/{+path}","compare_url":"https://api.github.com/repos/otland/forgottenserver/compare/{base}...{head}","merges_url":"https://api.github.com/repos/otland/forgottenserver/merges","archive_url":"https://api.github.com/repos/otland/forgottenserver/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/otland/forgottenserver/downloads","issues_url":"https://api.github.com/repos/otland/forgottenserver/issues{/number}","pulls_url":"https://api.github.com/repos/otland/forgottenserver/pulls{/number}","milestones_url":"https://api.github.com/repos/otland/forgottenserver/milestones{/number}","notifications_url":"https://api.github.com/repos/otland/forgottenserver/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/otland/forgottenserver/labels{/name}","releases_url":"https://api.github.com/repos/otland/forgottenserver/releases{/id}","created_at":"2013-07-01T01:57:06Z","updated_at":"2015-11-26T18:12:19Z","pushed_at":"2015-12-03T21:02:22Z","git_url":"git://github.com/otland/forgottenserver.git","ssh_url":"git@github.com:otland/forgottenserver.git","clone_url":"https://github.com/otland/forgottenserver.git","svn_url":"https://github.com/otland/forgottenserver","homepage":"","size":16480,"stargazers_count":283,"watchers_count":283,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":311,"mirror_url":null,"open_issues_count":142,"forks":311,"open_issues":142,"watchers":283,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/otland/forgottenserver/pulls/1628"},"html":{"href":"https://github.com/otland/forgottenserver/pull/1628"},"issue":{"href":"https://api.github.com/repos/otland/forgottenserver/issues/1628"},"comments":{"href":"https://api.github.com/repos/otland/forgottenserver/issues/1628/comments"},"review_comments":{"href":"https://api.github.com/repos/otland/forgottenserver/pulls/1628/comments"},"review_comment":{"href":"https://api.github.com/repos/otland/forgottenserver/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/otland/forgottenserver/pulls/1628/commits"},"statuses":{"href":"https://api.github.com/repos/otland/forgottenserver/statuses/25a52dc06ef5c633e79a34eabebbb099c1084f68"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":10,"additions":1050,"deletions":11,"changed_files":33}}