Skip to content

Commit

Permalink
Merge pull request #331 from vincent4vx/feature-living-chest
Browse files Browse the repository at this point in the history
feat(fight): Handle living chest
  • Loading branch information
vincent4vx authored Feb 6, 2024
2 parents 454bdb7 + 3ba9d52 commit ca57a1c
Show file tree
Hide file tree
Showing 49 changed files with 965 additions and 328 deletions.
1 change: 1 addition & 0 deletions src/main/java/fr/quatrevieux/araknemu/game/GameModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ private void configureServices(ContainerConfigurator configurator) {
simulator.register(125, new AlterCharacteristicSimulator()); // vitality
simulator.register(126, new AlterCharacteristicSimulator()); // intelligence
simulator.register(138, new AlterCharacteristicSimulator(2)); // percent damage
simulator.register(176, new AlterCharacteristicSimulator(20)); // discernment
simulator.register(178, new AlterCharacteristicSimulator(8)); // heal
simulator.register(182, new AddMaxSummonedCreatureSimulator(10)); // summoned creature
simulator.register(606, new AlterCharacteristicSimulator()); // Wisdom not dispellable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* This file is part of Araknemu.
*
* Araknemu is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Araknemu is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Araknemu. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (c) 2017-2024 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.misc;

import fr.quatrevieux.araknemu.game.fight.castable.BaseCastScope;
import fr.quatrevieux.araknemu.game.fight.castable.Castable;
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
import fr.quatrevieux.araknemu.game.fight.castable.effect.EffectValue;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffEffect;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;

/**
* Buff effect for adding discernment points to a target
* When casted on a summon creature, the created will be allowed to get drops, which will be given to the summoner
*
* @see fr.quatrevieux.araknemu.game.fight.fighter.FighterCharacteristics#alterDiscernment(int)
*/
public final class AddDiscernmentHandler implements EffectHandler, BuffHook {
@Override
public void handle(FightCastScope cast, BaseCastScope<Fighter, FightCell>.EffectScope effect) {
throw new UnsupportedOperationException("Add discernment should be used as buff");
}

@Override
public void buff(FightCastScope cast, BaseCastScope<Fighter, FightCell>.EffectScope effect) {
final SpellEffect spellEffect = effect.effect();
final Castable action = cast.action();
final Fighter caster = cast.caster();

EffectValue.forEachTargets(spellEffect, caster, cast.targets(), (target, effectValue) -> {
target.buffs().add(new Buff(
BuffEffect.fixed(spellEffect, effectValue.value()),
action,
caster,
target,
this
));
});
}

@Override
public void onBuffStarted(Buff buff) {
buff.target().characteristics().alterDiscernment(buff.effect().min());
}

@Override
public void onBuffTerminated(Buff buff) {
buff.target().characteristics().alterDiscernment(-buff.effect().min());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,13 @@ public Type type() {
public List<DropReward> rewards() {
return rewards;
}

/**
* Apply all rewards
*/
public void apply() {
for (DropReward reward : rewards) {
reward.apply();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package fr.quatrevieux.araknemu.game.fight.ending.reward;

import fr.quatrevieux.araknemu.game.fight.ending.EndFightResults;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;

/**
* Generate rewards for end fight
Expand All @@ -31,4 +32,14 @@ public interface RewardsGenerator {
* @param results The end fight results
*/
public FightRewardsSheet generate(EndFightResults results);

/**
* Check if the given fighter can be rewarded
* Generally, it will check if the fighter is not a summon creature
*
* @param fighter The fighter to check
*
* @return true if the fighter can be rewarded (so it will be in the rewards sheet), false to ignore it
*/
public boolean supports(Fighter fighter);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import fr.quatrevieux.araknemu.game.fight.ending.reward.FightRewardsSheet;
import fr.quatrevieux.araknemu.game.fight.ending.reward.RewardType;
import fr.quatrevieux.araknemu.game.fight.ending.reward.RewardsGenerator;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -41,4 +42,9 @@ public FightRewardsSheet generate(EndFightResults results) {

return new FightRewardsSheet(results, FightRewardsSheet.Type.NORMAL, rewards);
}

@Override
public boolean supports(Fighter fighter) {
return !fighter.invoked();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,40 @@ public AddItems(ItemService service) {

@Override
public void apply(DropReward reward, Fighter fighter) {
fighter.apply(new FighterOperation() {
@Override
public void onPlayer(PlayerFighter fighter) {
final PlayerInventory inventory = fighter.player().inventory();

reward.items().forEach((itemId, quantity) -> {
for (int q = 0; q < quantity; ++q) {
inventory.add(service.create(itemId));
}
});
fighter.apply(new Operation(reward));
}

private class Operation implements FighterOperation {
private final DropReward reward;

public Operation(DropReward reward) {
this.reward = reward;
}

@Override
public void onPlayer(PlayerFighter fighter) {
final PlayerInventory inventory = fighter.player().inventory();

reward.items().forEach((itemId, quantity) -> {
for (int q = 0; q < quantity; ++q) {
inventory.add(service.create(itemId));
}
});
}

@Override
public void onGenericFighter(Fighter fighter) {
if (!fighter.invoked()) {
return;
}
});

final Fighter invoker = fighter.invoker();

if (invoker == null) {
return;
}

invoker.apply(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.fighter.operation.FighterOperation;
import fr.quatrevieux.araknemu.game.fight.fighter.player.PlayerFighter;
import org.checkerframework.checker.index.qual.Positive;

/**
* Add kamas to fighter
Expand All @@ -32,15 +33,36 @@ public final class AddKamas implements DropRewardAction {
public void apply(DropReward reward, Fighter fighter) {
final long kamas = reward.kamas();

if (kamas == 0) {
return;
if (kamas > 0) {
fighter.apply(new Operation(kamas));
}
}

private static class Operation implements FighterOperation {
private final @Positive long kamas;

public Operation(@Positive long kamas) {
this.kamas = kamas;
}

@Override
public void onPlayer(PlayerFighter fighter) {
fighter.player().inventory().addKamas(kamas);
}

fighter.apply(new FighterOperation() {
@Override
public void onPlayer(PlayerFighter fighter) {
fighter.player().inventory().addKamas(kamas);
@Override
public void onGenericFighter(Fighter fighter) {
if (!fighter.invoked()) {
return;
}
});

final Fighter invoker = fighter.invoker();

if (invoker == null) {
return;
}

invoker.apply(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import fr.quatrevieux.araknemu.game.fight.ending.reward.drop.DropReward;
import fr.quatrevieux.araknemu.game.fight.ending.reward.drop.action.DropRewardAction;
import fr.quatrevieux.araknemu.game.fight.ending.reward.drop.pvm.provider.DropRewardProvider;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -73,4 +74,10 @@ public FightRewardsSheet generate(EndFightResults results) {

return new FightRewardsSheet(results, FightRewardsSheet.Type.NORMAL, rewards);
}

@Override
public boolean supports(Fighter fighter) {
// Keep invocations (e.g. living chest)
return !fighter.invoked() || fighter.characteristics().discernment() > 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.fighter.monster.MonsterFighter;
import fr.quatrevieux.araknemu.game.fight.fighter.operation.FighterOperation;
import fr.quatrevieux.araknemu.game.fight.fighter.player.PlayerFighter;
import org.checkerframework.checker.index.qual.NonNegative;

import java.util.Collection;
import java.util.stream.IntStream;

/**
* Base formula for compute the Pvm experience
*/
public final class PvmXpProvider implements DropRewardProvider {
private static final double[] LVL_DEV_BONUS = { 3.5, 1.0, 1.1, 1.3, 2.2, 2.5, 2.8, 3.1 };

private final double rate;

public PvmXpProvider() {
Expand All @@ -47,7 +53,7 @@ public DropRewardProvider.Scope initialize(EndFightResults results) {
totalXp(results),
teamsLevelsRate(results),
teamLevelDeviationBonus(results),
results.winners().stream().mapToInt(Fighter::level).sum()
levels(results.winners()).sum()
);
}

Expand All @@ -56,53 +62,33 @@ private long totalXp(EndFightResults results) {
}

private double teamLevelDeviationBonus(EndFightResults results) {
final int level = results.winners().stream().mapToInt(Fighter::level).max().orElse(0) / 3;
final int level = levels(results.winners()).max().orElse(0) / 3;

int number = 0;

for (Fighter winner : results.winners()) {
if (winner.level() > level) {
if (!winner.invoked() && winner.level() > level) {
++number;
}
}

switch (number) {
case 1:
return 1.0;

case 2:
return 1.1;

case 3:
return 1.3;

case 4:
return 2.2;

case 5:
return 2.5;

case 6:
return 2.8;

case 7:
return 3.1;

default:
return 3.5;
}
return number >= LVL_DEV_BONUS.length ? LVL_DEV_BONUS[0] : LVL_DEV_BONUS[number];
}

private double teamsLevelsRate(EndFightResults results) {
final double winnersLevel = results.winners().stream().mapToInt(Fighter::level).sum();
final double loosersLevel = results.loosers().stream().mapToInt(Fighter::level).sum();
final double winnersLevel = levels(results.winners()).sum();
final double loosersLevel = levels(results.loosers()).sum();

return Math.min(
1.3,
1 + loosersLevel / winnersLevel
);
}

private IntStream levels(Collection<Fighter> fighters) {
return fighters.stream().filter(fighter -> !fighter.invoked()).mapToInt(Fighter::level);
}

private static class Scope implements DropRewardProvider.Scope {
private final long totalXp;
private final double teamsLevelsRate;
Expand All @@ -118,15 +104,23 @@ public Scope(long totalXp, double teamsLevelsRate, double teamLevelDeviationBonu

@Override
public void provide(DropReward reward) {
final long winXp = (long) (
totalXp
* teamsLevelsRate
* teamLevelDeviationBonus
* (1 + ((double) reward.fighter().level() / winnersLevel))
* (1 + (double) reward.fighter().characteristics().get(Characteristic.WISDOM) / 100)
);
reward.fighter().apply(new FighterOperation() {
@Override
public void onPlayer(PlayerFighter fighter) {
final long winXp = computeXp(fighter.level(), fighter.characteristics().get(Characteristic.WISDOM));

reward.setXp(Math.max(winXp, 0));
}
});
}

reward.setXp(Math.max(winXp, 0));
private long computeXp(int level, int wisdom) {
return (long) (totalXp
* teamsLevelsRate
* teamLevelDeviationBonus
* (1 + ((double) level / winnersLevel))
* (1 + (double) wisdom / 100)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public final void setInvoker(Fighter invoker) {
}

@Override
public @Nullable FighterData invoker() {
public @Nullable Fighter invoker() {
return invoker;
}

Expand Down
Loading

0 comments on commit ca57a1c

Please sign in to comment.