00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 package com.realtime.crossfire.jxclient.stats;
00023
00024 import com.realtime.crossfire.jxclient.guistate.ClientSocketState;
00025 import com.realtime.crossfire.jxclient.guistate.GuiStateListener;
00026 import com.realtime.crossfire.jxclient.guistate.GuiStateManager;
00027 import com.realtime.crossfire.jxclient.skills.Skill;
00028 import com.realtime.crossfire.jxclient.skills.SkillSet;
00029 import com.realtime.crossfire.jxclient.util.EventListenerList2;
00030 import java.util.Collection;
00031 import java.util.HashSet;
00032 import org.jetbrains.annotations.NotNull;
00033
00043 public class Stats {
00044
00048 public static final int CS_STAT_HP = 1;
00049
00053 public static final int CS_STAT_MAXHP = 2;
00054
00058 public static final int CS_STAT_SP = 3;
00059
00063 public static final int CS_STAT_MAXSP = 4;
00064
00068 public static final int CS_STAT_STR = 5;
00069
00073 public static final int CS_STAT_INT = 6;
00074
00078 public static final int CS_STAT_WIS = 7;
00079
00083 public static final int CS_STAT_DEX = 8;
00084
00088 public static final int CS_STAT_CON = 9;
00089
00093 public static final int CS_STAT_CHA = 10;
00094
00098 public static final int CS_STAT_EXP = 11;
00099
00103 public static final int C_STAT_EXP_NEXT_LEVEL = 0x10000;
00104
00108 public static final int CS_STAT_LEVEL = 12;
00109
00113 public static final int CS_STAT_WC = 13;
00114
00118 public static final int CS_STAT_AC = 14;
00119
00123 public static final int CS_STAT_DAM = 15;
00124
00128 public static final int CS_STAT_ARMOUR = 16;
00129
00133 public static final int CS_STAT_SPEED = 17;
00134
00138 public static final int CS_STAT_FOOD = 18;
00139
00143 public static final int C_STAT_LOWFOOD = 0x10003;
00144
00148 public static final int CS_STAT_WEAP_SP = 19;
00149
00154 public static final int CS_STAT_RANGE = 20;
00155
00159 public static final int CS_STAT_TITLE = 21;
00160
00164 public static final int CS_STAT_POW = 22;
00165
00169 public static final int CS_STAT_GRACE = 23;
00170
00174 public static final int CS_STAT_MAXGRACE = 24;
00175
00179 public static final int CS_STAT_FLAGS = 25;
00180
00184 public static final int CS_STAT_WEIGHT_LIM = 26;
00185
00189 public static final int C_STAT_WEIGHT = 257;
00190
00194 public static final int CS_STAT_EXP64 = 28;
00195
00199 public static final int CS_STAT_SPELL_ATTUNE = 29;
00200
00204 public static final int CS_STAT_SPELL_REPEL = 30;
00205
00209 public static final int CS_STAT_SPELL_DENY = 31;
00210
00214 public static final int CS_STAT_RACE_STR = 32;
00215
00219 public static final int CS_STAT_RACE_INT = 33;
00220
00224 public static final int CS_STAT_RACE_WIS = 34;
00225
00229 public static final int CS_STAT_RACE_DEX = 35;
00230
00234 public static final int CS_STAT_RACE_CON = 36;
00235
00239 public static final int CS_STAT_RACE_CHA = 37;
00240
00244 public static final int CS_STAT_RACE_POW = 38;
00245
00249 public static final int CS_STAT_BASE_STR = 39;
00250
00254 public static final int CS_STAT_BASE_INT = 40;
00255
00259 public static final int CS_STAT_BASE_WIS = 41;
00260
00264 public static final int CS_STAT_BASE_DEX = 42;
00265
00269 public static final int CS_STAT_BASE_CON = 43;
00270
00274 public static final int CS_STAT_BASE_CHA = 44;
00275
00279 public static final int CS_STAT_BASE_POW = 45;
00280
00284 public static final int CS_STAT_APPLIED_STR = 46;
00285
00289 public static final int CS_STAT_APPLIED_INT = 47;
00290
00294 public static final int CS_STAT_APPLIED_WIS = 48;
00295
00299 public static final int CS_STAT_APPLIED_DEX = 49;
00300
00304 public static final int CS_STAT_APPLIED_CON = 50;
00305
00309 public static final int CS_STAT_APPLIED_CHA = 51;
00310
00314 public static final int CS_STAT_APPLIED_POW = 52;
00315
00319 public static final int CS_STAT_GOLEM_HP = 53;
00320
00324 public static final int CS_STAT_GOLEM_MAXHP = 54;
00325
00329 public static final int CS_STAT_RESIST_START = 100;
00330
00334 public static final int CS_STAT_RESIST_END = 117;
00335
00339 public static final int CS_STAT_RES_PHYS = 100;
00340
00344 public static final int CS_STAT_RES_MAG = 101;
00345
00349 public static final int CS_STAT_RES_FIRE = 102;
00350
00354 public static final int CS_STAT_RES_ELEC = 103;
00355
00359 public static final int CS_STAT_RES_COLD = 104;
00360
00364 public static final int CS_STAT_RES_CONF = 105;
00365
00369 public static final int CS_STAT_RES_ACID = 106;
00370
00374 public static final int CS_STAT_RES_DRAIN = 107;
00375
00379 public static final int CS_STAT_RES_GHOSTHIT = 108;
00380
00384 public static final int CS_STAT_RES_POISON = 109;
00385
00389 public static final int CS_STAT_RES_SLOW = 110;
00390
00394 public static final int CS_STAT_RES_PARA = 111;
00395
00399 public static final int CS_STAT_RES_TURN_UNDEAD = 112;
00400
00404 public static final int CS_STAT_RES_FEAR = 113;
00405
00409 public static final int CS_STAT_RES_DEPLETE = 114;
00410
00414 public static final int CS_STAT_RES_DEATH = 115;
00415
00419 public static final int CS_STAT_RES_HOLYWORD = 116;
00420
00424 public static final int CS_STAT_RES_BLIND = 117;
00425
00429 public static final int FLOAT_MULTI = 100000;
00430
00434 public static final int RESIST_TYPES = 18;
00435
00440 public static final int C_STAT_POISONED = 256;
00441
00447 public static final int CS_NUM_SKILLS = 50;
00448
00454 public static final int CS_STAT_SKILLINFO = 140;
00455
00460 private boolean simpleWeaponSpeed = false;
00461
00465 @NotNull
00466 private final EventListenerList2<StatsListener> statsListeners = new EventListenerList2<StatsListener>(StatsListener.class);
00467
00471 @NotNull
00472 private final ExperienceTable experienceTable;
00473
00477 @NotNull
00478 private final SkillSet skillSet;
00479
00483 @NotNull
00484 private final int[] stats = new int[258];
00485
00489 private long exp = 0;
00490
00494 private long expNextLevel = 0;
00495
00499 @NotNull
00500 private String range = "";
00501
00505 @NotNull
00506 private String title = "";
00507
00511 @NotNull
00512 private String activeSkill = "";
00513
00517 @NotNull
00518 private final Collection<String> unhandledStats = new HashSet<String>(0);
00519
00524 @NotNull
00525 private final GuiStateListener guiStateListener = new GuiStateListener() {
00526
00527 @Override
00528 public void start() {
00529
00530 }
00531
00532 @Override
00533 public void metaserver() {
00534
00535 }
00536
00537 @Override
00538 public void preConnecting(@NotNull final String serverInfo) {
00539
00540 }
00541
00542 @Override
00543 public void connecting(@NotNull final String serverInfo) {
00544 reset();
00545 }
00546
00547 @Override
00548 public void connecting(@NotNull final ClientSocketState clientSocketState) {
00549
00550 }
00551
00552 @Override
00553 public void connected() {
00554
00555 }
00556
00557 @Override
00558 public void connectFailed(@NotNull final String reason) {
00559
00560 }
00561
00562 };
00563
00570 public Stats(@NotNull final ExperienceTable experienceTable, @NotNull final SkillSet skillSet, @NotNull final GuiStateManager guiStateManager) {
00571 this.experienceTable = experienceTable;
00572 this.skillSet = skillSet;
00573 guiStateManager.addGuiStateListener(guiStateListener);
00574 }
00575
00582 public void setSimpleWeaponSpeed(final boolean simpleWeaponSpeed) {
00583 if (this.simpleWeaponSpeed == simpleWeaponSpeed) {
00584 return;
00585 }
00586
00587 this.simpleWeaponSpeed = simpleWeaponSpeed;
00588 for (final StatsListener statsListener : statsListeners.getListeners()) {
00589 statsListener.simpleWeaponSpeedChanged(this.simpleWeaponSpeed);
00590 }
00591 }
00592
00596 private void reset() {
00597 for (final StatsListener statsListener : statsListeners.getListeners()) {
00598 statsListener.reset();
00599 }
00600 for (int statNo = 0; statNo < stats.length; statNo++) {
00601 setStat(statNo, 0);
00602 }
00603 setExperience(0);
00604 setRange("");
00605 setTitle("");
00606 setActiveSkill("");
00607 }
00608
00614 public int getStat(final int statNo) {
00615 return stats[statNo];
00616 }
00617
00623 public double getFloatStat(final int statNo) {
00624 return (double)stats[statNo]/FLOAT_MULTI;
00625 }
00626
00632 public void setStat(final int statNo, final int value) {
00633 if (stats[statNo] == value) {
00634 return;
00635 }
00636
00637 stats[statNo] = value;
00638 for (final StatsListener statsListener : statsListeners.getListeners()) {
00639 statsListener.statChanged(statNo, stats[statNo]);
00640 }
00641 }
00642
00647 @NotNull
00648 public String getTitle() {
00649 return title;
00650 }
00651
00657 @NotNull
00658 public String getRange() {
00659 return range;
00660 }
00661
00666 @NotNull
00667 public String getActiveSkill() {
00668 return activeSkill;
00669 }
00670
00675 private void setTitle(@NotNull final String title) {
00676 if (this.title.equals(title)) {
00677 return;
00678 }
00679
00680 this.title = title;
00681 for (final StatsListener statsListener : statsListeners.getListeners()) {
00682 statsListener.titleChanged(this.title);
00683 }
00684 }
00685
00691 private void setRange(@NotNull final String range) {
00692 if (this.range.equals(range)) {
00693 return;
00694 }
00695
00696 this.range = range;
00697 for (final StatsListener statsListener : statsListeners.getListeners()) {
00698 statsListener.rangeChanged(this.range);
00699 }
00700 }
00701
00706 public void setActiveSkill(@NotNull final String activeSkill) {
00707 if (this.activeSkill.equals(activeSkill)) {
00708 return;
00709 }
00710
00711 this.activeSkill = activeSkill;
00712 for (final StatsListener statsListener : statsListeners.getListeners()) {
00713 statsListener.activeSkillChanged(this.activeSkill);
00714 }
00715 }
00716
00721 public long getExperience() {
00722 return exp;
00723 }
00724
00729 private void setExperience(final long exp) {
00730 if (this.exp == exp) {
00731 return;
00732 }
00733
00734 this.exp = exp;
00735 for (final StatsListener statsListener : statsListeners.getListeners()) {
00736 statsListener.experienceChanged(this.exp);
00737 }
00738
00739 calculateExperienceToNextLevel();
00740 }
00741
00746 public long getExperienceNextLevel() {
00747 return expNextLevel;
00748 }
00749
00753 private void calculateExperienceToNextLevel() {
00754 final long newExpNextLevel = experienceTable.getExperienceToNextLevel(stats[CS_STAT_LEVEL], exp);
00755 if (expNextLevel == newExpNextLevel) {
00756 return;
00757 }
00758
00759 expNextLevel = newExpNextLevel;
00760 for (final StatsListener statsListener : statsListeners.getListeners()) {
00761 statsListener.experienceNextLevelChanged(expNextLevel);
00762 }
00763 }
00764
00769 public void addCrossfireStatsListener(@NotNull final StatsListener statsListener) {
00770 statsListeners.add(statsListener);
00771 }
00772
00777 public void removeCrossfireStatsListener(@NotNull final StatsListener statsListener) {
00778 statsListeners.remove(statsListener);
00779 }
00780
00785 public double getWeaponSpeed() {
00786 final double weaponSpeed = getFloatStat(CS_STAT_WEAP_SP);
00787 if (simpleWeaponSpeed) {
00788 return weaponSpeed;
00789 }
00790
00791 if (weaponSpeed < 0.001) {
00792 return 0;
00793 }
00794
00795 return getFloatStat(CS_STAT_SPEED)/weaponSpeed;
00796 }
00797
00803 public void setStatInt2(final int stat, final short param) {
00804 switch (stat) {
00805 case CS_STAT_HP:
00806 case CS_STAT_MAXHP:
00807 case CS_STAT_SP:
00808 case CS_STAT_MAXSP:
00809 case CS_STAT_STR:
00810 case CS_STAT_INT:
00811 case CS_STAT_WIS:
00812 case CS_STAT_DEX:
00813 case CS_STAT_CON:
00814 case CS_STAT_CHA:
00815 case CS_STAT_LEVEL:
00816 case CS_STAT_WC:
00817 case CS_STAT_AC:
00818 case CS_STAT_DAM:
00819 case CS_STAT_ARMOUR:
00820 case CS_STAT_FOOD:
00821 case CS_STAT_POW:
00822 case CS_STAT_GRACE:
00823 case CS_STAT_MAXGRACE:
00824 case CS_STAT_RACE_STR:
00825 case CS_STAT_RACE_INT:
00826 case CS_STAT_RACE_WIS:
00827 case CS_STAT_RACE_DEX:
00828 case CS_STAT_RACE_CON:
00829 case CS_STAT_RACE_CHA:
00830 case CS_STAT_RACE_POW:
00831 case CS_STAT_BASE_STR:
00832 case CS_STAT_BASE_INT:
00833 case CS_STAT_BASE_WIS:
00834 case CS_STAT_BASE_DEX:
00835 case CS_STAT_BASE_CON:
00836 case CS_STAT_BASE_CHA:
00837 case CS_STAT_BASE_POW:
00838 case CS_STAT_APPLIED_STR:
00839 case CS_STAT_APPLIED_INT:
00840 case CS_STAT_APPLIED_WIS:
00841 case CS_STAT_APPLIED_DEX:
00842 case CS_STAT_APPLIED_CON:
00843 case CS_STAT_APPLIED_CHA:
00844 case CS_STAT_APPLIED_POW:
00845 case CS_STAT_GOLEM_HP:
00846 case CS_STAT_GOLEM_MAXHP:
00847 setStat(stat, param);
00848 if (stat == CS_STAT_LEVEL) {
00849 calculateExperienceToNextLevel();
00850 }
00851 break;
00852
00853 case CS_STAT_FLAGS:
00854 setStat(stat, param&0xFFFF);
00855 break;
00856
00857 default:
00858 if (CS_STAT_RESIST_START <= stat && stat < CS_STAT_RESIST_START+RESIST_TYPES) {
00859 setStat(stat, param);
00860 } else {
00861 reportUnhandledStat(stat, "int2");
00862 }
00863 break;
00864 }
00865 }
00866
00872 public void setStatInt4(final int stat, final int param) {
00873 switch (stat) {
00874 case CS_STAT_EXP:
00875 setExperience(param&0xFFFFFFFFL);
00876 break;
00877
00878 case CS_STAT_SPEED:
00879 case CS_STAT_WEAP_SP:
00880 case CS_STAT_WEIGHT_LIM:
00881 case CS_STAT_SPELL_ATTUNE:
00882 case CS_STAT_SPELL_REPEL:
00883 case CS_STAT_SPELL_DENY:
00884 setStat(stat, param);
00885 break;
00886
00887 default:
00888 reportUnhandledStat(stat, "int4");
00889 break;
00890 }
00891 }
00892
00898 public void setStatInt8(final int stat, final long param) {
00899 switch (stat) {
00900 case CS_STAT_EXP64:
00901 setExperience(param);
00902 break;
00903
00904 default:
00905 reportUnhandledStat(stat, "int8");
00906 break;
00907 }
00908 }
00909
00915 public void setStatString(final int stat, @NotNull final String param) {
00916 switch (stat) {
00917 case CS_STAT_RANGE:
00918 setRange(param);
00919 break;
00920
00921 case CS_STAT_TITLE:
00922 setTitle(param);
00923 break;
00924
00925 default:
00926 reportUnhandledStat(stat, "string");
00927 break;
00928 }
00929 }
00930
00937 public void setStatSkill(final int stat, final int level, final long experience) {
00938 if (CS_STAT_SKILLINFO <= stat && stat < CS_STAT_SKILLINFO+CS_NUM_SKILLS) {
00939 final Skill sk = skillSet.getSkill(stat);
00940 if (sk == null) {
00941 System.err.println("ignoring skill value for unknown skill "+stat);
00942 } else {
00943 sk.set(level, experience);
00944 }
00945 } else {
00946 reportUnhandledStat(stat, "skill");
00947 }
00948 }
00949
00955 private void reportUnhandledStat(final int stat, @NotNull final String type) {
00956 if (unhandledStats.add(type+"-"+stat)) {
00957 System.err.println("Warning: unhandled stat "+stat+" of type "+type);
00958 }
00959 }
00960
00961 }