/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2016 Evan Debenham
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
*/
package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfCorruption;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndItem;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.watabou.noosa.audio.Sample;
import com.watabou.noosa.particles.Emitter;
import com.watabou.noosa.particles.PixelParticle;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
import java.util.ArrayList;
public class MagesStaff extends MeleeWeapon {
private Wand wand;
public static final String AC_IMBUE = "IMBUE";
public static final String AC_ZAP = "ZAP";
private static final float STAFF_SCALE_FACTOR = 0.75f;
{
image = ItemSpriteSheet.MAGES_STAFF;
tier = 1;
defaultAction = AC_ZAP;
usesTargeting = true;
unique = true;
bones = false;
}
public MagesStaff() {
wand = null;
}
@Override
public int max(int lvl) {
return 3*(tier+1) + //6 base damage, down from 10
lvl*(tier+1); //scaling unaffected
}
public MagesStaff(Wand wand){
this();
wand.identify();
wand.cursed = false;
this.wand = wand;
wand.maxCharges = Math.min(wand.maxCharges + 1, 10);
wand.curCharges = wand.maxCharges;
name = Messages.get(wand, "staff_name");
}
@Override
public ArrayList actions(Hero hero) {
ArrayList actions = super.actions( hero );
actions.add(AC_IMBUE);
if (wand!= null && wand.curCharges > 0) {
actions.add( AC_ZAP );
}
return actions;
}
@Override
public void activate( Char ch ) {
if(wand != null) wand.charge( ch, STAFF_SCALE_FACTOR );
}
@Override
public void execute(Hero hero, String action) {
super.execute(hero, action);
if (action.equals(AC_IMBUE)) {
curUser = hero;
GameScene.selectItem(itemSelector, WndBag.Mode.WAND, Messages.get(this, "prompt"));
} else if (action.equals(AC_ZAP)){
if (wand == null) {
GameScene.show(new WndItem(null, this, true));
return;
}
wand.execute(hero, AC_ZAP);
}
}
@Override
public void proc(Char attacker, Char defender, int damage) {
if (wand != null && Dungeon.hero.subClass == HeroSubClass.BATTLEMAGE) {
if (wand.curCharges < wand.maxCharges) wand.partialCharge += 0.33f;
ScrollOfRecharging.charge((Hero)attacker);
wand.onHit(this, attacker, defender, damage);
}
super.proc(attacker, defender, damage);
}
@Override
public boolean collect( Bag container ) {
if (super.collect(container)) {
if (container.owner != null && wand != null) {
wand.charge(container.owner, STAFF_SCALE_FACTOR);
}
return true;
} else {
return false;
}
}
@Override
public void onDetach( ) {
if (wand != null) wand.stopCharging();
}
public Item imbueWand(Wand wand, Char owner){
this.wand = null;
GLog.p( Messages.get(this, "imbue", wand.name()));
if (enchantment != null) {
GLog.w( Messages.get(this, "conflict") );
enchant(null);
}
//syncs the level of the two items.
int targetLevel = Math.max(this.level(), wand.level());
int staffLevelDiff = targetLevel - this.level();
if (staffLevelDiff > 0)
this.upgrade(staffLevelDiff);
else if (staffLevelDiff < 0)
this.degrade(Math.abs(staffLevelDiff));
int wandLevelDiff = targetLevel - wand.level();
if (wandLevelDiff > 0)
wand.upgrade(wandLevelDiff);
else if (wandLevelDiff < 0)
wand.degrade(Math.abs(wandLevelDiff));
this.wand = wand;
wand.maxCharges = Math.min(wand.maxCharges + 1, 10);
wand.curCharges = wand.maxCharges;
wand.identify();
wand.cursed = false;
wand.charge(owner);
name = Messages.get(wand, "staff_name");
updateQuickslot();
return this;
}
@Override
public Item upgrade(boolean enchant) {
super.upgrade( enchant );
if (wand != null) {
int curCharges = wand.curCharges;
wand.upgrade();
//gives the wand one additional charge
wand.maxCharges = Math.min(wand.maxCharges + 1, 10);
wand.curCharges = Math.min(wand.curCharges + 1, 10);
updateQuickslot();
}
return this;
}
@Override
public Item degrade() {
super.degrade();
if (wand != null) {
int curCharges = wand.curCharges;
wand.degrade();
//gives the wand one additional charge
wand.maxCharges = Math.min(wand.maxCharges + 1, 10);
wand.curCharges = curCharges-1;
updateQuickslot();
}
return this;
}
@Override
public String status() {
if (wand == null) return super.status();
else return wand.status();
}
@Override
public String info() {
String info = super.info();
if (wand == null){
info += "\n\n" + Messages.get(this, "no_wand");
}
return info;
}
@Override
public Emitter emitter() {
if (wand == null) return null;
Emitter emitter = new Emitter();
emitter.pos(12.5f, 2.5f);
emitter.fillTarget = false;
emitter.pour(StaffParticleFactory, 0.06f);
return emitter;
}
private static final String WAND = "wand";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(WAND, wand);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
wand = (Wand) bundle.get(WAND);
if (wand != null) {
wand.maxCharges = Math.min(wand.maxCharges + 1, 10);
name = Messages.get(wand, "staff_name");
}
}
private final WndBag.Listener itemSelector = new WndBag.Listener() {
@Override
public void onSelect( final Item item ) {
if (item != null) {
if (!item.isIdentified()) {
GLog.w(Messages.get(MagesStaff.class, "id_first"));
return;
} else if (item.cursed){
GLog.w(Messages.get(MagesStaff.class, "cursed"));
return;
}
if (wand == null){
applyWand((Wand)item);
} else {
GameScene.show(
new WndOptions("",
Messages.get(MagesStaff.class, "warning"),
Messages.get(MagesStaff.class, "yes"),
Messages.get(MagesStaff.class, "no")) {
@Override
protected void onSelect(int index) {
if (index == 0) {
applyWand((Wand)item);
}
}
}
);
}
}
}
private void applyWand(Wand wand){
Sample.INSTANCE.play(Assets.SND_EVOKE);
ScrollOfUpgrade.upgrade(curUser);
evoke(curUser);
Dungeon.quickslot.clearItem(wand);
wand.detach(curUser.belongings.backpack);
Badges.validateTutorial();
imbueWand((Wand) wand, curUser);
updateQuickslot();
}
};
private final Emitter.Factory StaffParticleFactory = new Emitter.Factory() {
@Override
//reimplementing this is needed as instance creation of new staff particles must be within this class.
public void emit( Emitter emitter, int index, float x, float y ) {
StaffParticle c = (StaffParticle)emitter.getFirstAvailable(StaffParticle.class);
if (c == null) {
c = new StaffParticle();
emitter.add(c);
}
c.reset(x, y);
}
@Override
//some particles need light mode, others don't
public boolean lightMode() {
return !((wand instanceof WandOfDisintegration)
|| (wand instanceof WandOfCorruption)
|| (wand instanceof WandOfRegrowth));
}
};
//determines particle effects to use based on wand the staff owns.
public class StaffParticle extends PixelParticle{
private float minSize;
private float maxSize;
public float sizeJitter = 0;
public StaffParticle(){
super();
}
public void reset( float x, float y ) {
revive();
speed.set(0);
this.x = x;
this.y = y;
if (wand != null)
wand.staffFx( this );
}
public void setSize( float minSize, float maxSize ){
this.minSize = minSize;
this.maxSize = maxSize;
}
public void setLifespan( float life ){
lifespan = left = life;
}
public void shuffleXY(float amt){
x += Random.Float(-amt, amt);
y += Random.Float(-amt, amt);
}
public void radiateXY(float amt){
float hypot = (float)Math.hypot(speed.x, speed.y);
this.x += speed.x/hypot*amt;
this.y += speed.y/hypot*amt;
}
@Override
public void update() {
super.update();
size(minSize + (left / lifespan)*(maxSize-minSize) + Random.Float(sizeJitter));
}
}
}