Changeset 9 for trunk/src/game/ArenaTeam.cpp
- Timestamp:
- 11/19/08 13:22:41 (17 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/game/ArenaTeam.cpp
r2 r9 52 52 return false; 53 53 54 sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART( CaptainGuid));54 sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid)); 55 55 56 56 CaptainGuid = captainGuid; … … 139 139 pl->SetInArenaTeam(Id, GetSlot()); 140 140 pl->SetArenaTeamIdInvited(0); 141 } 142 else 143 { 144 Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid); 141 // personal rating 142 pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500); 145 143 } 146 144 … … 150 148 if(pl) 151 149 pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1); 152 else 153 Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, PlayerGuid); 154 } 150 } 151 152 // setuint32valueindb is asynch, can't be used here 153 Tokens tokens; 154 if(!Player::LoadValuesArrayFromDB(tokens,PlayerGuid)) 155 return false; 156 157 // arena team id 158 uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6); 159 char buf[11]; 160 snprintf(buf,11,"%u",Id); 161 tokens[index] = buf; 162 // pers rating 163 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5; 164 buf[11]; 165 snprintf(buf,11,"%u",1500); 166 tokens[index] = buf; 167 // hide promote/remove buttons 168 if(CaptainGuid != PlayerGuid) 169 { 170 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6); 171 buf[11]; 172 snprintf(buf,11,"%u",1); 173 tokens[index] = buf; 174 } 175 176 Player::SaveValuesArrayInDB(tokens,PlayerGuid); 177 155 178 return true; 156 179 } … … 158 181 bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId) 159 182 { 160 LoadStatsFromDB(ArenaTeamId);161 LoadMembersFromDB(ArenaTeamId);162 163 // 0 1 2 3 4 5 6 7 8164 183 QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId); 165 184 … … 181 200 delete result; 182 201 202 // only load here, so additional checks can be made 203 LoadStatsFromDB(ArenaTeamId); 204 LoadMembersFromDB(ArenaTeamId); 205 206 if(!GetMembersSize()) 207 { 208 // arena team is empty, delete from db 209 CharacterDatabase.BeginTransaction(); 210 CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId); 211 CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId); 212 CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId); 213 CharacterDatabase.CommitTransaction(); 214 // return false 215 return false; 216 } 217 183 218 return true; 184 219 } … … 208 243 Field *fields; 209 244 210 QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);245 QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId); 211 246 if(!result) 212 247 return; … … 217 252 ArenaTeamMember newmember; 218 253 newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); 254 // check if this member is in this arenateam 255 // based on character data field 256 if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId) 257 { 258 // the player's registered arena team for this slot isn't this team, so delete member info from here 259 CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId); 260 continue; 261 } 219 262 LoadPlayerStats(&newmember); 220 263 newmember.played_week = fields[1].GetUInt32(); … … 277 320 278 321 Player *player = objmgr.GetPlayer(guid); 322 // this will be ugly. because of the asynchronous sql handling, we have to set all the fields of the player at once, and save them at once, or else the save will only modify the last field. 323 // rip off of setuint32valueindb 279 324 if(player) 280 325 { 281 326 player->SetInArenaTeam(0, GetSlot()); 282 327 player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0); 283 } 284 else 285 { 286 Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid); 287 } 288 289 CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid)); 328 // delete all info regarding this team 329 for(int i = 0; i < 6; ++i) 330 { 331 player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0); 332 } 333 } 334 335 // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player 336 Tokens tokens; 337 if(!Player::LoadValuesArrayFromDB(tokens,guid)) 338 return; 339 340 for(int i = 0; i < 6; ++i) 341 { 342 uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i; 343 char buf[11]; 344 snprintf(buf,11,"%u",0); 345 tokens[index] = buf; 346 } 347 348 Player::SaveValuesArrayInDB(tokens,guid); 349 350 // only delete from this arena team! 351 CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid)); 290 352 } 291 353 … … 314 376 CharacterDatabase.BeginTransaction(); 315 377 CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id); 378 CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id); 316 379 CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id); 317 380 CharacterDatabase.CommitTransaction(); … … 343 406 data << uint32(itr->played_season); // played this season 344 407 data << uint32(itr->wons_season); // wins this season 345 data << uint32( 0); // personal rating?408 data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5)); // personal rating? 346 409 } 347 410 else … … 357 420 data << uint32(itr->played_season); // played this season 358 421 data << uint32(itr->wons_season); // wins this season 359 data << uint32( 0); // personal rating?422 data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid)); // personal rating? 360 423 } 361 424 } … … 392 455 } 393 456 457 void ArenaTeam::NotifyStatsChanged() 458 { 459 // this is called after a rated match ended 460 // updates arena team stats for every member of the team (not only the ones who participated!) 461 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 462 { 463 Player * plr=objmgr.GetPlayer(itr->guid); 464 if(plr) 465 Stats(plr->GetSession()); 466 } 467 } 468 394 469 void ArenaTeam::InspectStats(WorldSession *session, uint64 guid) 395 470 { … … 399 474 data << uint32(GetId()); // arena team id 400 475 data << uint32(stats.rating); // rating 401 data << uint32(stats.games); // games 402 data << uint32(stats.wins); // wins 403 data << uint32(stats.played); // played (count of all games, that played...) 404 data << uint32(0); // 2.3.3 personal rating? 476 data << uint32(stats.played); // season played 477 data << uint32(stats.wins2); // season wins 478 uint32 participated = 0; 479 for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr) 480 { 481 if(itr->guid == guid) 482 { 483 participated = itr->played_season; 484 break; 485 } 486 } 487 data << uint32(participated); // played (count of all games, that the inspected member participated...) 488 data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid)); // unk, 2.3.3 (personal rating?) 489 405 490 session->SendPacket(&data); 406 491 } … … 495 580 } 496 581 582 uint32 ArenaTeam::GetPoints(uint32 MemberRating) 583 { 584 // returns how many points would be awarded with this team type with this rating 585 float points; 586 587 uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating; 588 589 if(rating<=1500) 590 { 591 points = (float)rating * 0.22f + 14.0f; 592 } 593 else 594 { 595 points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating)); 596 } 597 598 // type penalties for <5v5 teams 599 if(Type == ARENA_TEAM_2v2) 600 points *= 0.76f; 601 else if(Type == ARENA_TEAM_3v3) 602 points *= 0.88f; 603 604 return (uint32) points; 605 } 606 607 float ArenaTeam::GetChanceAgainst(uint32 rating) 608 { 609 // returns the chance to win against a team with the given rating, used in the rating adjustment calculation 610 // ELO system 611 return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f)); 612 } 613 614 int32 ArenaTeam::WonAgainstChance(float chance) 615 { 616 // called when the team has won, and had 'chance' calculated chance to beat the opponent 617 // calculate the rating modification (ELO system with k=32) 618 int32 mod = (int32)floor(32.0f * (1.0f - chance)); 619 // modify the team stats accordingly 620 stats.rating += mod; 621 stats.games += 1; 622 stats.wins += 1; 623 stats.played += 1; 624 stats.wins2 += 1; 625 /* this should be done in .flusharenapoints; not a breaker though. 626 uint32 higher_rank = 0; 627 QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id); 628 if(result) 629 { 630 higher_rank = result->Fetch()->GetUInt32(); 631 delete result; 632 } 633 stats.rank = higher_rank + 1;*/ 634 // return the rating change, used to display it on the results screen 635 return mod; 636 } 637 638 int32 ArenaTeam::LostAgainstChance(float chance) 639 { 640 // called when the team has lost, and had 'chance' calculated chance to beat the opponent 641 // calculate the rating modification (ELO system with k=32) 642 int32 mod = (int32)ceil(32.0f * (0.0f - chance)); 643 // modify the team stats accordingly 644 stats.rating += mod; 645 stats.games += 1; 646 stats.played += 1; 647 /* uint32 higher_rank = 0; 648 QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id); 649 if(result) 650 { 651 higher_rank = result->Fetch()->GetUInt32(); 652 delete result; 653 } 654 stats.rank = higher_rank + 1;*/ 655 // return the rating adjustment for display 656 return mod; 657 } 658 659 void ArenaTeam::MemberLost(Player * plr, uint32 againstrating) 660 { 661 // called for each participant of a match after losing 662 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 663 { 664 if(itr->guid == plr->GetGUID()) 665 { 666 // update personal rating 667 int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5); 668 float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f)); 669 int32 mod = (int32)ceil(32.0f * (0.0f - chance)); 670 personalrating += mod; 671 if(personalrating < 0) 672 personalrating = 0; 673 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating); 674 // update personal played stats 675 itr->played_week +=1; 676 itr->played_season +=1; 677 // update the unit fields 678 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week); 679 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season); 680 return; 681 } 682 } 683 } 684 685 void ArenaTeam::MemberWon(Player * plr, uint32 againstrating) 686 { 687 // called for each participant after winning a match 688 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 689 { 690 if(itr->guid == plr->GetGUID()) 691 { 692 // update personal rating 693 int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5); 694 float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f)); 695 int32 mod = (int32)floor(32.0f * (1.0f - chance)); 696 personalrating += mod; 697 if(personalrating < 0) 698 personalrating = 0; 699 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating); 700 // update personal stats 701 itr->played_week +=1; 702 itr->played_season +=1; 703 itr->wons_season += 1; 704 itr->wons_week += 1; 705 // update unit fields 706 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week); 707 plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season); 708 return; 709 } 710 } 711 } 712 713 void ArenaTeam::UpdateArenaPointsHelper() 714 { 715 // called after a match has ended and the stats are already modified 716 // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons) 717 // 10 played games per week is a minimum 718 if(stats.games < 10) 719 return; 720 // to get points, a player has to participate in at least 30% of the matches 721 uint32 min_plays = ceil(stats.games * 0.3); 722 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 723 { 724 // the player participated in enough games, update his points 725 if(itr->played_week >= min_plays) 726 { 727 // do it separately for online and offline players 728 // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries 729 // offline player cant have a personal rating not matching the db 730 Player * plr = objmgr.GetPlayer(itr->guid); 731 uint32 points_to_add = 0; 732 if(plr) 733 points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5)); 734 else 735 points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid)); 736 // it's enough to set the points in memory, the saving is done in separate function 737 CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid); 738 } 739 // the player failed to participate in enough games, so no points for him 740 else 741 { 742 CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid); 743 } 744 } 745 } 746 747 void ArenaTeam::SaveToDB() 748 { 749 // save team and member stats to db 750 // called after a match has ended 751 CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId()); 752 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 753 { 754 CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, Id, itr->guid); 755 } 756 } 757 758 void ArenaTeam::FinishWeek() 759 { 760 stats.games = 0; // played this week 761 stats.wins = 0; // wins this week 762 for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) 763 { 764 itr->played_week = 0; 765 itr->wons_week = 0; 766 } 767 } 768 497 769 /* 498 770 arenateam fields (id from 2.3.3 client): 499 771 1414 - arena team id 2v2 500 772 1415 - 0=captain, 1=member 501 1416 - played this season502 1417 - played this week773 1416 - played this week 774 1417 - played this season 503 775 1418 - unk 504 1419 - unk776 1419 - personal arena rating 505 777 1420 - arena team id 3v3 506 778 1421 - 0=captain, 1=member 507 1422 - played this season508 1423 - played this week779 1422 - played this week 780 1423 - played this season 509 781 1424 - unk 510 1425 - unk782 1425 - personal arena rating 511 783 1426 - arena team id 5v5 512 784 1427 - 0=captain, 1=member 513 1428 - played this season514 1429 - played this week785 1428 - played this week 786 1429 - played this season 515 787 1430 - unk 516 1431 - unk788 1431 - personal arena rating 517 789 */