// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.datatype; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; import java.util.Locale; import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.ResourceFactory; import org.infinity.resource.StructEntry; /** * Manages IDS target type and value fields. */ public class IdsTargetType extends Bitmap { public static final String DEFAULT_NAME_TYPE = "IDS target"; public static final String DEFAULT_NAME_VALUE = "IDS value"; public static final String DEFAULT_NAME_UNUSED = "Unused"; public static final String DEFAULT_ACTOR_NAME = "Actor's name"; public static final String DEFAULT_ACTOR_SCRIPTNAME = "Actor's script name"; public static final String DEFAULT_SECOND_IDS = "EA.IDS"; public static final String[] DEFAULT_IDS_LIST = {"", "", "", "GENERAL.IDS", "RACE.IDS", "CLASS.IDS", "SPECIFIC.IDS", "GENDER.IDS", "ALIGNMEN.IDS"}; private final int index; private boolean updateIdsValues; // defines whether to update the "IDS value" field automatically /** * Constructs an IDS type field with the default list of IDS entries. */ public IdsTargetType(ByteBuffer buffer, int offset, int size) { this(null, buffer, offset, size, null, -1, null, false); } /** * Constructs an IDS type field with the default list of IDS entries. */ public IdsTargetType(StructEntry parent, ByteBuffer buffer, int offset, int size) { this(parent, buffer, offset, size, null, -1, null, false); } /** * Constructs an IDS type field with the default list of IDS entries. */ public IdsTargetType(ByteBuffer buffer, int offset, int size, String name) { this(null, buffer, offset, size, name, -1, null, false); } /** * Constructs an IDS type field with the default list of IDS entries. */ public IdsTargetType(StructEntry parent, ByteBuffer buffer, int offset, int size, String name) { this(parent, buffer, offset, size, name, -1, null, false); } /** * Constructs an IDS type field with the default list of IDS entries and optional modifications. * @param secondIds Replace IDS resource at index = 2 by the specified resource. (Default: EA.IDS) * @param targetActor If {@code true}, Enhanced Editions will use index 10 for * Actor's name strrefs and index 11 for Actor's script name. */ public IdsTargetType(ByteBuffer buffer, int offset, int size, String name, String secondIds, boolean targetActor) { this(null, buffer, offset, size, name, -1, secondIds, targetActor); } /** * Constructs an IDS type field with the default list of IDS entries and optional modifications. * @param secondIds Replace IDS resource at index = 2 by the specified resource. (Default: EA.IDS) * @param targetActor If {@code true}, Enhanced Editions will use index 10 for * Actor's name strrefs and index 11 for Actor's script name. */ public IdsTargetType(StructEntry parent, ByteBuffer buffer, int offset, int size, String name, String secondIds, boolean targetActor) { this(parent, buffer, offset, size, name, -1, secondIds, targetActor); } /** * Constructs an IDS type field with the default list of IDS entries and optional modifications. * @param idx An optional number added to the field name. (Default: -1 for none) * @param secondIds Replace IDS resource at index = 2 by the specified resource. (Default: EA.IDS) * @param targetActor If {@code true}, Enhanced Editions will use index 10 for * Actor's name strrefs and index 11 for Actor's script name. */ public IdsTargetType(ByteBuffer buffer, int offset, int size, String name, int idx, String secondIds, boolean targetActor) { this(null, buffer, offset, size, name, idx, secondIds, targetActor); } /** * Constructs an IDS type field with the default list of IDS entries and optional modifications. * @param idx An optional number added to the field name. (Default: -1 for none) * @param secondIds Replace IDS resource at index = 2 by the specified resource. (Default: EA.IDS) * @param targetActor If {@code true}, Enhanced Editions will use index 10 for * Actor's name strrefs and index 11 for Actor's script name. */ public IdsTargetType(StructEntry parent, ByteBuffer buffer, int offset, int size, String name, int idx, String secondIds, boolean targetActor) { super(parent, buffer, offset, size, createFieldName(name, idx, DEFAULT_NAME_TYPE), createIdsTypeTable(secondIds, targetActor)); this.index = idx; this.updateIdsValues = true; } /** Constructs an IDS type field with the specified list of IDS resource names. */ public IdsTargetType(ByteBuffer buffer, int offset, int size, String name, String[] ids) { super(buffer, offset, size, createFieldName(name, -1, DEFAULT_NAME_TYPE), (ids != null) ? ids : createIdsTypeTable(null, false)); this.index = -1; this.updateIdsValues = true; } //--------------------- Begin Interface Editable --------------------- @Override public boolean updateValue(AbstractStruct struct) { boolean retVal = super.updateValue(struct); if (updateIdsValues && retVal) { int valueOffset = getOffset() - getSize(); List<StructEntry> list = struct.getList(); for (int i = 0, size = list.size(); i < size; i++) { StructEntry entry = list.get(i); if (entry.getOffset() == valueOffset && entry instanceof Datatype) { ByteBuffer buffer = ((Datatype)entry).getDataBuffer(); StructEntry newEntry = createIdsValueFromType(buffer, 0); newEntry.setOffset(valueOffset); list.set(i, newEntry); // notifying listeners struct.fireTableRowsUpdated(i, i); } } } return retVal; } //--------------------- End Interface Editable --------------------- /** * Creates a fully initialized StructEntry object for IDS value, based on the currently selected * IDS type. Offset and size values will be derived from the data of this IDS type field. */ public StructEntry createIdsValueFromType(ByteBuffer buffer) { return createIdsValueFromType(buffer, getOffset() - getSize(), getSize(), null); } /** * Creates a fully initialized StructEntry object for IDS value, based on the currently selected * IDS type. Returns a DecNumber object for unsupported IDS types. */ public StructEntry createIdsValueFromType(ByteBuffer buffer, int offset) { return createIdsValueFromType(buffer, offset, getSize(), null); } /** * Creates a fully initialized StructEntry object for IDS value, based on the currently selected * IDS type. Returns a DecNumber object for unsupported IDS types. */ public StructEntry createIdsValueFromType(ByteBuffer buffer, int offset, int size, String name) { int value = getValue(); String type = getString(value); if (type != null) { if (ResourceFactory.resourceExists(type)) { return new IdsBitmap(buffer, offset, size, createFieldName(name, index, DEFAULT_NAME_VALUE), type); } else if (getSize() == 4 && value == 10 && !type.isEmpty()) { // Actor's name as Strref return new StringRef(buffer, offset, createFieldName(name, index, DEFAULT_ACTOR_NAME)); } } return new DecNumber(buffer, offset, size, createFieldName(name, index, DEFAULT_NAME_UNUSED)); } public StructEntry createResourceFromType(ByteBuffer buffer, int offset) { return createResourceFromType(buffer, offset, null); } /** * Creates a fully initialized StructEntry object for the resource field, based on the currently * selected IDS type. Only index 11 (Actor's script name) is currently supported. * Returns an Unknown object otherwise. */ public StructEntry createResourceFromType(ByteBuffer buffer, int offset, String name) { int value = getValue(); String type = getString(value); if (type != null) { if (value == 11 && !type.isEmpty() && !type.toUpperCase(Locale.ENGLISH).endsWith(".IDS")) { // Actor's script name return new TextString(buffer, offset, 8, createFieldName(name, index, DEFAULT_ACTOR_SCRIPTNAME)); } } return new Unknown(buffer, offset, 8, createFieldName(name, index, DEFAULT_NAME_UNUSED)); } /** Returns whether this IdsTargetType instance automatically updates the associated IDS value field. */ public boolean isUpdatingIdsValues() { return updateIdsValues; } /** Specify whether this IdsTargetType instance should automatically update the associated IDS value field. */ public void setUpdateIdsValues(boolean b) { updateIdsValues = b; } /** Returns an array of available IDS targets for the current game type. */ public static String[] createIdsTypeTable(String secondIds, boolean targetActor) { int len = DEFAULT_IDS_LIST.length; if (Profile.isEnhancedEdition()) { len++; if (targetActor) { len += 2; } } String[] retVal = Arrays.copyOf(DEFAULT_IDS_LIST, len); retVal[2] = (secondIds != null) ? secondIds : DEFAULT_SECOND_IDS; retVal[8] = Profile.getProperty(Profile.Key.GET_IDS_ALIGNMENT); if (Profile.isEnhancedEdition()) { retVal[9] = "KIT.IDS"; if (targetActor) { retVal[10] = DEFAULT_ACTOR_NAME; retVal[11] = DEFAULT_ACTOR_SCRIPTNAME; } } return retVal; } // Creates a valid field name from the specified arguments private static String createFieldName(String name, int index, String defName) { if (name == null) { name = (defName != null) ? defName : DEFAULT_NAME_TYPE; } return (index >= 0) ? (name + " " + index) : name; } }