Skip to content

Commit

Permalink
Punishment for visiting Kika clouds too frequently
Browse files Browse the repository at this point in the history
  • Loading branch information
AntumDeluge committed May 3, 2024
1 parent 846cbc0 commit d53cb31
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/games/stendhal/server/entity/item/scroll/BalloonScroll.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand All @@ -17,6 +17,7 @@
import games.stendhal.common.MathHelper;
import games.stendhal.server.core.events.DelayedPlayerTextSender;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.maps.kikareukin.islands.HeavenGateKeeper;

/**
* Represents the balloon that takes the player to 7 kikareukin clouds,
Expand Down Expand Up @@ -73,6 +74,13 @@ protected boolean useTeleportScroll(final Player player) {
}
return false;
}

if (!HeavenGateKeeper.requestEntrance(player)) {
// balloon is used if player was punished
removeOne();
return false;
}

long lastuse = -1;
if (player.hasQuest("balloon")) {
lastuse = Long.parseLong(player.getQuest("balloon"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/***************************************************************************
* Copyright © 2024 - Faiumoni e. V. *
***************************************************************************
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
package games.stendhal.server.maps.kikareukin.islands;

import games.stendhal.common.Level;
import games.stendhal.common.MathHelper;
import games.stendhal.common.NotificationType;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.core.engine.StendhalRPZone;
import games.stendhal.server.core.events.TurnListener;
import games.stendhal.server.core.events.TurnNotifier;
import games.stendhal.server.entity.npc.action.IncrementQuestAction;
import games.stendhal.server.entity.player.Player;


public class HeavenGateKeeper {

/** Slot name used for tracking requests. */
private static final String SLOT = "heaven_gatekeeper";
/** Name of entity that messages player. */
private static final String ENTITY_NAME = "Kikareukin's Gatekeeper";
/** Number of requests allowed before being punished. */
private static final short REQUEST_LIMIT = 3;
/** Time period in which player requests are tracked (4 days). */
private static final long TIME_BUFFER = MathHelper.MILLISECONDS_IN_ONE_DAY * 4;
/** XP modifier for trying to requesting too often (15% of excess). */
private static final float XP_MODIFIER = 0.15f;


/**
* Increments number of requests player has made.
*
* @param player
* Player requesting entrance.
*/
private static void addRequest(final Player player) {
final long timeFromRequestStart = System.currentTimeMillis() - HeavenGateKeeper.getRequestTime(player);
if (timeFromRequestStart > HeavenGateKeeper.TIME_BUFFER) {
// first request or time limit expired so reset so player isn't unnecessarily punished
player.setQuest(HeavenGateKeeper.SLOT, System.currentTimeMillis() + ";1");
} else {
new IncrementQuestAction(HeavenGateKeeper.SLOT, 1, 1).fire(player, null, null);
}
}

/**
* Retrieves the time period beginning when player made initial request.
*
* @param player
* Player requesting entrance.
* @return
* Time of initial request.
*/
private static long getRequestTime(final Player player) {
return MathHelper.parseLongDefault(player.getQuest(HeavenGateKeeper.SLOT, 0), 0);
}

/**
* Retrieves number of request player has made in the current time period.
*
* @param player
* Player requesting entrance.
* @return
* Request count.
*/
private static int getRequestCount(final Player player) {
return MathHelper.parseIntDefault(player.getQuest(HeavenGateKeeper.SLOT, 1), 0);
}

/**
* Punishment from heaven.
*
* - sent to afterlife
* - loses all but 1 HP
* - loses 15% of excess XP
*
* TODO:
* - add lightning (spell effect)
* - play thunder sound
*
* @param player
* Player being punished.
*/
private static void punish(final Player player) {
// send to afterlife
final StendhalRPZone afterlife = SingletonRepository.getRPWorld().getZone("int_afterlife");
if (afterlife != null) {
player.teleport(afterlife, 31, 23, player.getDirection(), null);
}
// set HP to 1 & subtract XP
final int xpStart = player.getXP();
// a percentage of XP based on difference requirement to next level (levels can be lost)
//final int xpDiff = (int) Math.floor(Level.getXPDiff(player.getLevel()-1) * HeavenGateKeeper.XP_MODIFIER);
final int xpBuffer = Math.max(xpStart - Level.getXP(player.getLevel()), 0);
// a percentage of player's gained XP relative to the current level (levels cannot be lost)
final int xpDiff = (int) Math.floor(xpBuffer * HeavenGateKeeper.XP_MODIFIER);
final int hpStart = player.getHP();
player.addXP(-xpDiff);
player.setHP(1);
final int xpLoss = xpStart - player.getXP();
final int hpLoss = hpStart - player.getHP();

NotificationType ntype = NotificationType.INFORMATION;
String msg = "It appears you you are not welcome in the clouds at this time.";
if (xpLoss > 0 || hpLoss > 0) {
ntype = NotificationType.NEGATIVE;
msg += " You lost ";
if (hpLoss > 0) {
msg += hpLoss + " health";
if (xpLoss > 0) {
msg += " and ";
}
}
if (xpLoss > 0) {
msg += xpLoss + " experience";
}
msg += ".";
}
player.sendPrivateText(ntype, msg);
}

/**
* Checks if player violates visit limit.
*
* @param player
* Player requesting entrance.
* @return
* `true` if player has made more than 3 requests within 4 days.
*/
private static boolean inViolation(final Player player) {
return HeavenGateKeeper.getRequestCount(player) > HeavenGateKeeper.REQUEST_LIMIT;
}

/**
* Requests entrance into heaven and punishes if necessary.
*
* @param player
* Player requesting entrance.
* @return
* Whether player can enter.
*/
public static boolean requestEntrance(final Player player) {
HeavenGateKeeper.addRequest(player);
if (HeavenGateKeeper.inViolation(player)) {
// first delay is to notify player, second is to apply punishment
final TurnNotifier notifier = SingletonRepository.getTurnNotifier();
final TurnListener listener = new TurnListener() {
private boolean notified = false;
@Override
public void onTurnReached(int currentTurn) {
if (!notified) {
player.sendPrivateText(NotificationType.PRIVMSG, HeavenGateKeeper.ENTITY_NAME,
"You have worn out your welcome and shall be punished for your greed!");
notified = true;
notifier.notifyInTurns(10, this);
} else {
HeavenGateKeeper.punish(player);
}
}
};
notifier.notifyInTurns(10, listener);
return false;
}
return true;
}
}

0 comments on commit d53cb31

Please sign in to comment.