2
0
Эх сурвалжийг харах

Partial Stack Exp operations. Can't really test it as battle is unplayable atm.

DjWarmonger 14 жил өмнө
parent
commit
252cee96f5

+ 1 - 1
lib/CCreatureHandler.h

@@ -114,7 +114,7 @@ public:
 
 	std::map<TBonusType, std::pair<std::string, std::string> > stackBonuses; // bonus => name, description
 	std::vector<std::vector<ui32>> expRanks; // stack experience needed for certain rank, index 0 for other tiers (?)
-	std::vector<ui32> maxExpPerBattle; //tiers same as above
+	std::vector<ui32> maxExpPerBattle; //%, tiers same as above
 	si8 expAfterUpgrade;//multiplier in %
 
 	void loadCreatures();

+ 25 - 0
lib/CCreatureSet.cpp

@@ -218,10 +218,18 @@ void CCreatureSet::setStackCount(TSlot slot, TQuantity count)
 {
 	assert(hasStackAtSlot(slot));
 	assert(count > 0);
+	if (STACK_EXP)
+		stacks[slot]->experience *= ((stacks[slot]->count + count)/(float)stacks[slot]->count);
 	stacks[slot]->count = count;
 	armyChanged();
 }
 
+void CCreatureSet::giveStackExp(expType exp)
+{
+	for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); i++)
+		i->second->giveStackExp(exp);
+}
+
 void CCreatureSet::clear()
 {
 	while(!stacks.empty())
@@ -453,6 +461,19 @@ int CStackInstance::getExpRank() const
 	}
 }
 
+void CStackInstance::giveStackExp(expType exp)
+{
+	int level = type->level;
+	if (!iswith(level, 1, 7))
+		level = 0;
+
+	CCreatureHandler * creh = VLC->creh;
+
+	amin(exp, (expType)creh->expRanks[level].back()); //prevent exp overflow due to different types
+	amin(exp, (exp * creh->maxExpPerBattle[level])/100);
+	amin(experience += exp, creh->expRanks[level].back()); //can't get more exp than this limit
+}
+
 void CStackInstance::setType(int creID)
 {
 	setType(VLC->creh->creatures[creID]);
@@ -461,7 +482,11 @@ void CStackInstance::setType(int creID)
 void CStackInstance::setType(const CCreature *c)
 {
 	if(type)
+	{
 		detachFrom(const_cast<CCreature*>(type));
+		if (type->isMyUpgrade(c) && STACK_EXP)
+			experience *= VLC->creh->expAfterUpgrade / 100.0f;
+	}
 
 	type = c;
 

+ 2 - 0
lib/CCreatureSet.h

@@ -59,6 +59,7 @@ public:
 	void setType(int creID);
 	void setType(const CCreature *c);
 	void setArmyObj(const CArmedInstance *ArmyObj);
+	void giveStackExp(expType exp);
 	bool valid(bool allowUnrandomized) const;
 	virtual std::string nodeName() const OVERRIDE;
 	void deserializationFix();
@@ -118,6 +119,7 @@ public:
 	void setStackCount(TSlot slot, TQuantity count); //stack must exist!
 	CStackInstance *detachStack(TSlot slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted)
 	void setStackType(TSlot slot, const CCreature *type);
+	void giveStackExp(expType exp);
 
 	//derivative 
 	void eraseStack(TSlot slot); //slot must be occupied

+ 27 - 19
lib/CObjectHandler.cpp

@@ -1179,7 +1179,7 @@ void CGHeroInstance::updateSkill(int which, int val)
 	int skillVal = 0;
 	switch (which)
 	{
-		case 1: //Archery
+		case ARCHERY:
 			switch (val)
 			{
 				case 1:
@@ -1190,27 +1190,29 @@ void CGHeroInstance::updateSkill(int which, int val)
 					skillVal = 50; break;
 			}
 			break;
-		case 2: //Logistics
+		case LOGISTICS:
 			skillVal = 10 * val; break;
-		case 5: //Navigation
+		case NAVIGATION:
 			skillVal = 50 * val; break;
-		case 8: //Mysticism
+		case MYSTICISM:
 			skillVal = val; break;
-		case 11: //eagle Eye
+		case EAGLE_EYE:
 			skillVal = 30 + 10 * val; break;
-		case 12: //Necromancy
+		case NECROMANCY:
 			skillVal = 10 * val; break;
-		case 22: //Offense
+		case LEARNING:
+			skillVal = 5 * val; break;
+		case OFFENCE:
 			skillVal = 10 * val; break;
-		case 23: //Armorer
+		case ARMORER:
 			skillVal = 5 * val; break;
-		case 24: //Intelligence
+		case INTELLIGENCE:
 			skillVal = 25 << (val-1); break;
-		case 25: //Sorcery
+		case SORCERY:
 			skillVal = 5 * val; break;
-		case 26: //Resistance
+		case RESISTANCE:
 			skillVal = 5 << (val-1); break;
-		case 27: //First Aid
+		case FIRST_AID:
 			skillVal = 25 + 25*val; break;
 	}
 	
@@ -1246,6 +1248,11 @@ int CGHeroInstance::getTotalStrength() const
 	return (int) ret;
 }
 
+expType CGHeroInstance::calculateXp(expType exp) const
+{
+	return exp * (100 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::LEARNING))/100.0f;
+}
+
 ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool) const
 {
 	si16 skill = -1; //skill level
@@ -2492,7 +2499,7 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 		case 100: //give exp
 			{
 				const CGHeroInstance *h = cb->getHero(heroID);
-				val = val*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
+				val = h->calculateXp(val);
 				InfoWindow iw;
 				iw.soundID = sound;
 				iw.components.push_back(Component(id,subid,val,0));
@@ -3836,7 +3843,7 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
 				sd.player = h->tempOwner;
 				sd.text << std::pair<ui8,ui32>(11,146);
 				sd.components.push_back(Component(2,6,val1,0));
-				int expVal = val2*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
+				expType expVal = h->calculateXp(val2);
 				sd.components.push_back(Component(5,0,expVal, 0));
 				sd.soundID = soundBase::chest;
 				boost::function<void(ui32)> fun = boost::bind(&CGPickable::chosen,this,_1,h->id);
@@ -3857,7 +3864,7 @@ void CGPickable::chosen( int which, int heroID ) const
 		cb->giveResource(cb->getOwner(heroID),6,val1);
 		break;
 	case 2: //player pick exp
-		cb->changePrimSkill(heroID, 4, val2*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f);
+		cb->changePrimSkill(heroID, 4, h->calculateXp(val2));
 		break;
 	default:
 		throw std::string("Unhandled treasure choice");
@@ -4374,7 +4381,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 	{
 		case 1: //experience
 		{
-			int expVal = rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
+			expType expVal = h->calculateXp(rVal);
 			cb->changePrimSkill(h->id, 4, expVal, false);
 			break;
 		}
@@ -4862,7 +4869,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 
 	if(gainedExp || changesPrimSkill || abilities.size())
 	{
-		expType expVal = gainedExp*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
+		expType expVal = h->calculateXp(gainedExp);
 		getText(iw,afterBattle,175,h);
 
 		if(expVal)
@@ -6165,8 +6172,10 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
 
 		if(xp)
 		{
+			xp = h->calculateXp(xp);
 			iw.text.addTxt(11,132);
 			iw.text.addReplacement(xp);
+			cb->changePrimSkill(h->ID, 4, xp, false);
 		}
 		else
 		{
@@ -6174,8 +6183,7 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
 		}
 	}
 	cb->showInfoDialog(&iw);
-	//////////////////////////////////////////////////////////////////////////
-	///TODO: WHAT WITH EXP? 
+
 }
 
 //bool IShipyard::validLocation() const

+ 1 - 0
lib/CObjectHandler.h

@@ -408,6 +408,7 @@ public:
 	static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
 	double getHeroStrength() const;
 	int getTotalStrength() const;
+	expType calculateXp(expType exp) const; //apply learning skill
 	ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = NULL) const; //returns level on which given spell would be cast by this hero (0 - none, 1 - basic etc); optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
 	bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
 	CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;

+ 7 - 3
server/CGameHandler.cpp

@@ -196,6 +196,8 @@ void CGameHandler::levelUpHero(int ID, int skill)
 void CGameHandler::levelUpHero(int ID)
 {
 	CGHeroInstance *hero = static_cast<CGHeroInstance *>(gs->map->objects[ID].get());
+	if (hero->battle)
+		tlog1<<"Battle found\n";
 	if (hero->exp < VLC->heroh->reqExp(hero->level+1)) // no more level-ups
 		return;
 		
@@ -287,7 +289,9 @@ void CGameHandler::changePrimSkill(int ID, int which, si64 val, bool abs)
 	sendAndApply(&sps);
 	if(which==4) //only for exp - hero may level up
 	{
+		//TODO: Stack Experience only after battle
 		levelUpHero(ID);
+		//TODO: Commander
 	}
 }
 
@@ -340,9 +344,9 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 	//end battle, remove all info, free memory
 	giveExp(*battleResult.data);
 	if (hero1)
-		battleResult.data->exp[0] *= (100+hero1->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;//sholar skill
+		battleResult.data->exp[0] = hero1->calculateXp(battleResult.data->exp[0]);//scholar skill
 	if (hero2)
-		battleResult.data->exp[1] *= (100+hero2->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f;
+		battleResult.data->exp[1] = hero2->calculateXp(battleResult.data->exp[1]);
 
 	ui8 sides[2];
 	for(int i=0; i<2; ++i)
@@ -4687,7 +4691,7 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc
 	int dump, exp;
 	market->getOffer(crid, 0, dump, exp, CREATURE_EXP);
 	exp *= count;
-	changePrimSkill(hero->id, 4, exp*(100+hero->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f);
+	changePrimSkill(hero->id, 4, hero->calculateXp(exp));
 
 	return true;
 }