/*
* Copyright (c) 2005 (Mike) Maurice Kienenberger (mkienenb@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.gamenet.application.mm8leveleditor.data.mm6;
import java.util.ArrayList;
import java.util.List;
import org.gamenet.application.mm8leveleditor.data.GameVersion;
import org.gamenet.swing.controls.ComparativeTableControl;
import org.gamenet.swing.controls.Vertex3DValueHolder;
import org.gamenet.util.ByteConversions;
public class Item implements Vertex3DValueHolder
{
private static final int ITEM_RECORD_LENGTH_MM6 = 100; // 100 bytes
private static final int ITEM_RECORD_LENGTH_MM7 = 112; // 112 bytes
private static final int RANGE_TYPE_TOUCH = 0;
private static final int RANGE_TYPE_SHORT = 1;
private static final int RANGE_TYPE_MEDIUM = 2;
private static final int RANGE_TYPE_LONG = 3;
private static final int ATTRIBUTE_TYPE_IDENTIFIED = 0x0001;
private static final int ATTRIBUTE_TYPE_BROKEN = 0x0002;
private static final int ATTRIBUTE_TYPE_CURSED = 0x0004;
private static final int ATTRIBUTE_TYPE_TEMPORARY_POWER = 0x0008;
private static final int ATTRIBUTE_TYPE_SPECIAL_EFFECT_1 = 0x0010;
private static final int ATTRIBUTE_TYPE_SPECIAL_EFFECT_2 = 0x0020;
private static final int ATTRIBUTE_TYPE_SPECIAL_EFFECT_3 = 0x0040;
private static final int ATTRIBUTE_TYPE_SPECIAL_EFFECT_4 = 0x0080;
private static final int ATTRIBUTE_TYPE_STOLEN = 0x0100;
private static final int ATTRIBUTE_TYPE_HARDENED = 0x0200;
private static final int TYPE_OFFSET = 0; // two bytes
private static final int ID_OFFSET = 2; // two bytes, DOBJLIST?
private static final int X_OFFSET = 4; // four signed bytes, neg is west
private static final int Y_OFFSET = 8; // four signed bytes, neg is south
private static final int Z_OFFSET = 12; // four signed bytes
private static final int VELOCITY_X_OFFSET = 16; // 2 bytes
private static final int VELOCITY_Y_OFFSET = 18; // 2 bytes
private static final int VELOCITY_Z_OFFSET = 20; // 2 bytes
private static final int FACING_OFFSET = 22; // 2 bytes
private static final int SOUND_NUMBER_OFFSET = 24; // 2 bytes
private static final int ATTRIBUTES_OFFSET = 26; // 2 bytes
private static final int ROOM_OFFSET = 28; // 2 bytes
private static final int AGE_OFFSET = 30; // 2 bytes
private static final int MAX_AGE_OFFSET = 32; // 2 bytes
private static final int LIGHT_MULTIPLIER_OFFSET = 34; // 2 bytes
private static final int ITEM_NUMBER_OFFSET = 36; // four bytes
private static final int STANDARD_MAGIC_CLASS_OFFSET = 40; // four bytes
private static final int VALUE_MODIFIER_OFFSET = 44; // four bytes
private static final int SPECIAL_MAGIC_CLASS_OFFSET = 48; // four bytes
private static final int AMOUNT_OF_GOLD_OFFSET = 48; // 4 bytes
private static final int CHARGES_OFFSET = 52; // four bytes
private static final int ATTRIBUTE_OFFSET = 56; // four bytes
private static final int BODY_LOCATION_OFFSET = 60; // 1 byte
private static final int MAXIMUM_CHARGES_OFFSET = 61; // 1 byte
private static final int OWNER_OFFSET = 62; // 1 byte
private static final int PADDING_OFFSET = 63; // 1 byte
private static final int SPELL_TYPE_OFFSET_MM6 = 64; // 4 bytes
private static final int SPELL_SKILL_LEVEL_OFFSET_MM6 = 68; // 4 bytes
private static final int SPELL_LEVEL_OFFSET_MM6 = 72; // 4 bytes
private static final int SPELL_EFFECT_OFFSET_OFFSET_MM6 = 76; // 4 bytes
// private static final int OWNER_OFFSET_MM6 = 80; // 4 bytes
private static final int TARGET_OFFSET_MM6 = 80; // 4 byte
private static final int RANGE_OFFSET_MM6 = 84; // 1 byte
private static final int ATTACK_TYPE_OFFSET_MM6 = 85; // 1 byte
private static final int PADDING_OFFSET_MM6 = 86; // 2 bytes
private static final int STARTING_X_OFFSET_MM6 = 88; // 4 bytes
private static final int STARTING_Y_OFFSET_MM6 = 92; // 4 bytes
private static final int STARTING_Z_OFFSET_MM6 = 96; // 4 bytes
private static final int TIME_OFFSET_MM7 = 64; // 8 bytes // mm7,mm8
private static final int SPELL_TYPE_OFFSET_MM7 = 72; // 4 bytes
private static final int SPELL_SKILL_LEVEL_OFFSET_MM7 = 76; // 4 bytes
private static final int SPELL_LEVEL_OFFSET_MM7 = 80; // 4 bytes
private static final int SPELL_EFFECT_OFFSET_OFFSET_MM7 = 84; // 4 bytes
private static final int OWNER_OFFSET_MM7 = 88; // 4 bytes
private static final int TARGET_OFFSET_MM7 = 92; // 4 byte
private static final int RANGE_OFFSET_MM7 = 96; // 1 byte
private static final int ATTACK_TYPE_OFFSET_MM7 = 97; // 1 byte
private static final int PADDING_OFFSET_MM7 = 98; // 2 bytes
private static final int STARTING_X_OFFSET_MM7 = 100; // 4 bytes
private static final int STARTING_Y_OFFSET_MM7 = 104; // 4 bytes
private static final int STARTING_Z_OFFSET_MM7 = 108; // 4 bytes
private int gameVersion = 0;
private byte itemData[] = null;
private int goldAmount = 0;
private int bodyLocation = 0;
// ChestContents/shop/character item
public Item(int gameVersion)
{
super();
this.gameVersion = gameVersion;
if (GameVersion.MM6 == gameVersion)
this.itemData = new byte[ITEM_RECORD_LENGTH_MM6];
else this.itemData = new byte[ITEM_RECORD_LENGTH_MM7];
}
// Outdoor item
public Item(int gameVersion, int offset, int itemNumber, int stdMagicClass, int stdMagicBonus, int amountOfGold, int charges, int bodyLocation)
{
this(gameVersion);
this.setItemNumber(itemNumber);
this.setStandardMagicClass(stdMagicClass);
this.setStandardMagicBonus(stdMagicBonus);
this.setGoldAmount(amountOfGold);
this.setSpecialMagicClass(amountOfGold);
this.setCharges(charges);
this.setBodyLocation(bodyLocation);
}
// Outdoor item
public Item(int gameVersion, int itemNumber, int pictureNumber, int x, int y, int z, int stdMagicClass, int stdMagicBonus, int amountOfGold, int charges)
{
this(gameVersion);
this.setItemNumber(itemNumber);
this.setPictureNumber(pictureNumber);
this.setX(x);
this.setY(y);
this.setZ(z);
this.setStandardMagicClass(stdMagicClass);
this.setStandardMagicBonus(stdMagicBonus);
this.setGoldAmount(amountOfGold);
this.setSpecialMagicClass(amountOfGold);
this.setCharges(charges);
}
public int initialize(byte dataSrc[], int offset)
{
System.arraycopy(dataSrc, offset, this.itemData, 0, this.itemData.length);
offset += this.itemData.length;
return offset;
}
public static int populateObjects(int gameVersion, byte[] data, int offset, List itemList)
{
int itemCount = ByteConversions.getIntegerInByteArrayAtPosition(data, offset);
offset += 4;
for (int itemIndex = 0; itemIndex < itemCount; ++itemIndex)
{
Item item = new Item(gameVersion);
itemList.add(item);
offset = item.initialize(data, offset);
}
return offset;
}
/**
* @param newData
* @param offset
* @param itemArray
* @return offset
*/
public static int updateData(byte[] newData, int offset, List itemList)
{
ByteConversions.setIntegerInByteArrayAtPosition(itemList.size(), newData, offset);
offset += 4;
for (int itemIndex = 0; itemIndex < itemList.size(); ++itemIndex)
{
Item item = (Item)itemList.get(itemIndex);
System.arraycopy(item.getItemData(), 0, newData, offset, item.getItemData().length);
offset += item.getItemData().length;
}
return offset;
}
public byte[] getItemData()
{
return this.itemData;
}
public int getItemNumber()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), ITEM_NUMBER_OFFSET);
}
public void setItemNumber(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), ITEM_NUMBER_OFFSET);
}
public int getPictureNumber()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), ID_OFFSET);
}
public void setPictureNumber(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), ID_OFFSET);
}
public int getStandardMagicClass()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), STANDARD_MAGIC_CLASS_OFFSET);
}
public void setStandardMagicClass(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), STANDARD_MAGIC_CLASS_OFFSET);
}
public int getStandardMagicBonus()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), VALUE_MODIFIER_OFFSET);
}
public void setStandardMagicBonus(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), VALUE_MODIFIER_OFFSET);
}
public int getSpecialMagicClass()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), SPECIAL_MAGIC_CLASS_OFFSET);
}
public void setSpecialMagicClass(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), SPECIAL_MAGIC_CLASS_OFFSET);
}
public int getCharges()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), CHARGES_OFFSET);
}
public void setCharges(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), CHARGES_OFFSET);
}
public int getX()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), X_OFFSET);
}
public void setX(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), X_OFFSET);
}
public int getY()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), Y_OFFSET);
}
public void setY(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), Y_OFFSET);
}
public int getZ()
{
return ByteConversions.getIntegerInByteArrayAtPosition(getItemData(), Z_OFFSET);
}
public void setZ(int value)
{
ByteConversions.setIntegerInByteArrayAtPosition(value, getItemData(), Z_OFFSET);
}
public int getGoldAmount()
{
return this.goldAmount;
}
public void setGoldAmount(int goldAmount)
{
this.goldAmount = goldAmount;
}
public int getBodyLocation()
{
return this.bodyLocation;
}
public void setBodyLocation(int bodyLocation)
{
this.bodyLocation = bodyLocation;
}
// Unknown things to decode
public static List getOffsetList(int gameVersion)
{
List offsetList = new ArrayList();
offsetList.add(new ComparativeTableControl.OffsetData(TYPE_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "type"));
offsetList.add(new ComparativeTableControl.OffsetData(ID_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "ID"));
offsetList.add(new ComparativeTableControl.OffsetData(X_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "x"));
offsetList.add(new ComparativeTableControl.OffsetData(Y_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "y"));
offsetList.add(new ComparativeTableControl.OffsetData(Z_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "z"));
offsetList.add(new ComparativeTableControl.OffsetData(VELOCITY_X_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "velocity x"));
offsetList.add(new ComparativeTableControl.OffsetData(VELOCITY_Y_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "velocity y"));
offsetList.add(new ComparativeTableControl.OffsetData(VELOCITY_Z_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "velocity z"));
offsetList.add(new ComparativeTableControl.OffsetData(FACING_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "facing"));
offsetList.add(new ComparativeTableControl.OffsetData(SOUND_NUMBER_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "sound #"));
offsetList.add(new ComparativeTableControl.OffsetData(ATTRIBUTES_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "attributes"));
offsetList.add(new ComparativeTableControl.OffsetData(ROOM_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "room"));
offsetList.add(new ComparativeTableControl.OffsetData(AGE_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "age"));
offsetList.add(new ComparativeTableControl.OffsetData(MAX_AGE_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "max age"));
offsetList.add(new ComparativeTableControl.OffsetData(LIGHT_MULTIPLIER_OFFSET, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "light multiplier"));
offsetList.add(new ComparativeTableControl.OffsetData(ITEM_NUMBER_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "item #"));
offsetList.add(new ComparativeTableControl.OffsetData(STANDARD_MAGIC_CLASS_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "std magic class"));
offsetList.add(new ComparativeTableControl.OffsetData(VALUE_MODIFIER_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "value modifier"));
offsetList.add(new ComparativeTableControl.OffsetData(SPECIAL_MAGIC_CLASS_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spc magic class/gold"));
offsetList.add(new ComparativeTableControl.OffsetData(CHARGES_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "charges"));
offsetList.add(new ComparativeTableControl.OffsetData(ATTRIBUTE_OFFSET, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "attributes"));
offsetList.add(new ComparativeTableControl.OffsetData(BODY_LOCATION_OFFSET, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "body location"));
offsetList.add(new ComparativeTableControl.OffsetData(MAXIMUM_CHARGES_OFFSET, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "max charges"));
offsetList.add(new ComparativeTableControl.OffsetData(OWNER_OFFSET, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "owner"));
offsetList.add(new ComparativeTableControl.OffsetData(PADDING_OFFSET, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "padding"));
if (GameVersion.MM6 == gameVersion)
{
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_TYPE_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell type"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_SKILL_LEVEL_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell skill"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_LEVEL_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell level"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_X_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting x"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_Y_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting y"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_Z_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting z"));
// one of the below isn't right
// offsetList.add(new ComparativeTableControl.OffsetData(OWNER_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "owner"));
offsetList.add(new ComparativeTableControl.OffsetData(TARGET_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "target"));
offsetList.add(new ComparativeTableControl.OffsetData(RANGE_OFFSET_MM6, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "range"));
offsetList.add(new ComparativeTableControl.OffsetData(ATTACK_TYPE_OFFSET_MM6, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "attack type"));
offsetList.add(new ComparativeTableControl.OffsetData(PADDING_OFFSET_MM6, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "padding"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_EFFECT_OFFSET_OFFSET_MM6, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "offset"));
}
else
{
offsetList.add(new ComparativeTableControl.OffsetData(TIME_OFFSET_MM7, 8, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "time"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_TYPE_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell type"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_SKILL_LEVEL_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell skill"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_LEVEL_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "spell level"));
offsetList.add(new ComparativeTableControl.OffsetData(OWNER_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "owner"));
offsetList.add(new ComparativeTableControl.OffsetData(TARGET_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "target"));
offsetList.add(new ComparativeTableControl.OffsetData(RANGE_OFFSET_MM7, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "range"));
offsetList.add(new ComparativeTableControl.OffsetData(ATTACK_TYPE_OFFSET_MM7, 1, ComparativeTableControl.REPRESENTATION_BYTE_DEC, "attack type"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_X_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting x"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_Y_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting y"));
offsetList.add(new ComparativeTableControl.OffsetData(STARTING_Z_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "starting z"));
offsetList.add(new ComparativeTableControl.OffsetData(PADDING_OFFSET_MM7, 2, ComparativeTableControl.REPRESENTATION_SHORT_DEC, "padding"));
offsetList.add(new ComparativeTableControl.OffsetData(SPELL_EFFECT_OFFSET_OFFSET_MM7, 4, ComparativeTableControl.REPRESENTATION_INT_DEC, "offset"));
}
return offsetList;
}
public static ComparativeTableControl.DataSource getComparativeDataSource(final List itemList)
{
return new ComparativeTableControl.DataSource()
{
public int getRowCount()
{
return itemList.size();
}
public byte[] getData(int dataRow)
{
Item item = (Item)itemList.get(dataRow);
return item.getItemData();
}
public int getAdjustedDataRowIndex(int dataRow)
{
return dataRow;
}
public String getIdentifier(int dataRow)
{
Item item = (Item)itemList.get(dataRow);
return String.valueOf(dataRow) + " - id #" + item.getItemNumber();
}
public int getOffset(int dataRow)
{
return 0;
}
};
}
public static int getRecordSize(int gameVersion)
{
if (GameVersion.MM6 == gameVersion)
return ITEM_RECORD_LENGTH_MM6;
else return ITEM_RECORD_LENGTH_MM7;
}
public int getGameVersion()
{
return this.gameVersion;
}
}