WENOPAL

02 · Scripts: ítems

Escribe ítems de Build 42 sabiendo qué hace cada campo, qué clase Java crea ItemType, cómo usar tags y cómo lee el motor los scripts.

Curso técnico · Build 42 · Actualizado el

Objetivo: escribir ítems sabiendo qué hace cada campo, de dónde sacar los valores y cómo los lee el motor. Al final CursoLab tiene tres ítems propios que puedes usar en la partida.

1. La sintaxis

Los scripts son .txt con una gramática propia (no es JSON ni Lua):

module CursoLab
{
    imports
    {
        Base,
    }

    item Sopaipilla
    {
        DisplayCategory = Food,
        ItemType = base:food,
        Weight = 0.1,
        Icon = Sopaipilla,
        Tags = base:cookable;base:hasprotein,
        HungerChange = -10,
    }
}

Reglas que el parser hace cumplir (y que dan errores raros si las rompes):

  • Bloques con llaves: module, y adentro item, model, craftRecipe, entity, sound, vehicle...
  • Clave = valor,: una por línea, con coma al final. Los valores no llevan comillas.
  • Listas con ;: Tags = base:a;base:b. La coma separa campos, el punto y coma separa elementos.
  • Comentarios con /* ... */. Los archivos generados del juego no tienen comentarios con //: no te arriesgues, usa /* */.
  • Escribe las claves exactamente como el juego (Researchablerecipes, no ResearchableRecipes): además de evitar sorpresas, así las puedes buscar en _juego/.

imports { Base } permite referirse a cosas de Base sin el prefijo en algunos lugares (modelos, por ejemplo). En las recetas de B42 escribe siempre el nombre completo (Base.Apple): un nombre sin módulo en craftRecipe es el clásico "World loading could not proceed, there are script load errors".

2. ItemType: qué clase de Java va a ser tu ítem

ItemType decide qué clase de Java se instancia cuando el ítem existe en el mundo, y por lo tanto qué campos entiende y qué métodos puedes llamar desde Lua. En B42 (contado en scripts/generated/items/):

ItemTypeÍtems en el juegoEjemplos
base:clothing1.395ropa, mochilas que se ponen
base:normal1.099herramientas, materiales, la lupa
base:food722comida y bebida
base:literature561libros, revistas, mapas de tesoro
base:weapon409armas cuerpo a cuerpo y de fuego
base:moveable393muebles que se recogen
base:container308bolsos, cajas
base:drainable150ítems con usos: estropajo, cinta, pilas
base:radio, map, weaponpart, key, alarmclock, animal...pocoscasos especiales

Cada tipo corresponde a una clase en zombie.inventory.types (por ejemplo Food, HandWeapon, Clothing, DrainableComboItem). En el módulo 08 lo confirmas abriendo el .jar: en zombie.scripting.objects.Item.InstanceItem hay una cadena de if (this.itemType == ItemType.FOOD) { item = new Food(...) } else if ... que crea el objeto Java según el tipo.

Consecuencia práctica: HungerChange en un ítem base:normal no hace nada; el campo existe en el script pero la clase que lo usaría no se crea. Si un campo "no funciona", revisa primero el tipo.

3. Los campos que vas a usar siempre

CampoQué haceDetalle
DisplayCategoryCategoría en el inventario y en el crafteoFood, Tool, Weapon, Material...
WeightPeso en kg0.1 es liviano; un bate pesa 2.0
IconÍconoIcon = X busca textures/Item_X.png (Tocomples Food, uno de nuestros mods, trae 161 así)
TagsPara qué cuenta el ítemLo que usan las recetas y el Lua para encontrar ítems (sección 4)
TooltipClave del texto que sale al pasar el mouseTooltip_CursoLab_Sopaipilla, en Translate/<IDIOMA>/Tooltip.json
WorldStaticModelModelo 3D en el suelomódulo 05
StaticModelModelo 3D en la manomódulo 05

El nombre visible no va en el script: va en Translate/<IDIOMA>/ItemName.json con la clave "CursoLab.Sopaipilla". Los ítems del juego no usan DisplayName; nuestros mods lo traen igual como respaldo (ejercicio 2.4).

Comida (base:food)

Mira la manzana (items/food.txt, item Apple):

HungerChange = -16.0,     ← negativo = quita hambre
ThirstChange = -7.0,
Calories = 95.0, Carbohydrates = 25.13, Lipids = 0.31, Proteins = 0.47,
DaysFresh = 5,            ← días hasta empezar a ponerse rancia
DaysTotallyRotten = 8,    ← días hasta estar podrida
EvolvedRecipe = Cake:16;FruitSalad:8;...   ← en qué comidas compuestas entra y cuánto aporta

El Completo Italiano de Tocomples Food tiene HungerChange = -50, Calories = 668 y UnhappyChange = -12: está bien calibrado contra la comida del juego.

Armas (base:weapon)

El bate (items/weapon.txt, item BaseballBat) es la mejor referencia:

MinDamage = 0.8, MaxDamage = 1.1,
MinRange = 0.61, MaxRange = 1.25,
BaseSpeed = 1.0, MinimumSwingtime = 3.0,
CriticalChance = 40.0, CritDmgMultiplier = 2.0,
ConditionMax = 15, ConditionLowerChanceOneIn = 20,   ← se desgasta 1 de cada 20 golpes
MaxHitcount = 2,                                      ← zombis por golpe
Categories = base:blunt,                              ← qué habilidad entrena

Los números se entienden comparando: haz una tabla con 5 armas parecidas antes de inventar los tuyos (la referencia del sitio, wenopal.work/referencia/items/, sirve para eso).

4. Tags: el idioma común entre scripts, recetas y Lua

Un tag dice para qué cuenta un ítem. Es la pieza más importante para la compatibilidad:

  • Las recetas piden tags, no ítems: item 1 tags[base:screwdriver] mode:keep acepta cualquier destornillador, incluido el tuyo si lleva base:screwdriver.
  • El Lua del juego pregunta por tags: item:hasTag(ItemTag.MAGNIFIER) (eso es lo que hace útil a la lupa, módulo 01).
  • En B42 los tags tienen espacio de nombres: base:hammer. En Lua el mismo tag se escribe como enum: ItemTag.HAMMER.

La lista completa de tags y qué ítems los tienen está en wenopal.work/referencia/tags.html.

5. Cómo lo lee el motor

  1. Al arrancar, Java recorre todos los .txt de media/scripts/ (juego + mods) y los tokeniza.
  2. Junta los bloques por module y crea un Item de script por cada item (la plantilla). Un campo que no reconoce se ignora (a veces con un aviso en console.txt).
  3. Cuando un ítem aparece en el mundo, se crea un InventoryItem (de la clase que dice ItemType) a partir de esa plantilla.

Por eso hay dos objetos distintos que vas a ver en Lua: la plantilla (ScriptManager.instance:getItem("Base.Apple")) y el ítem concreto en un inventario (InventoryItem, con su condición, su frescura, etc.).


Ejercicios

Para cada ítem: agrégalo en 42/media/scripts/CursoLab_items.txt, ponle nombre en Translate/ES/ItemName.json y Translate/EN/ItemName.json, y créalo desde la consola:

lua
getPlayer():getInventory():AddItem("CursoLab.Sopaipilla")

Ejercicio 2.1 · Una comida

CursoLab.Sopaipilla: debe quitar algo de hambre, durar 2 días fresca y 4 hasta podrirse, y aportar calorías razonables para su tamaño.

Listo cuando: puedes comerla, el hambre baja, y al pasar el tiempo (acelera el reloj desde el menú debug) cambia a rancia y a podrida.

Ejercicio 2.2 · Una herramienta que el juego reconozca

CursoLab.DestornilladorChino: un destornillador barato, liviano, que se rompe rápido.

Listo cuando: sirve para cualquier receta del juego que pida destornillador, sin tocar ninguna receta. (Pista: sección 4.)

Ejercicio 2.3 · Un arma calibrada

CursoLab.PaloDeEscoba: más rápido que el bate, menos daño, alcance parecido, se rompe antes.

  1. Arma una tabla con 5 armas contundentes del juego (daño, alcance, velocidad, durabilidad).
  2. Elige tus valores y justifica cada uno en un comentario /* */.
  3. Pruébalo contra zombis (menú debug → spawnear horda pequeña).

Listo cuando: se siente distinto del bate y tus números están dentro del rango del juego.

Ejercicio 2.4 · Romperlo a propósito

Haz cada uno de estos errores (uno a la vez), anota qué ves en pantalla y en console.txt, y vuelve a dejarlo bien:

  1. Olvida una coma al final de un campo.
  2. Escribe mal una clave (Weigth = 0.5).
  3. Pon ItemType = base:normal en la sopaipilla.
  4. Borra la entrada de ItemName.json (y prueba con y sin DisplayName en el script).
  5. Pon un Icon que no existe.

Listo cuando: tienes una tabla "síntoma → causa" propia. Te va a ahorrar horas.

Desafío 2

Escribe pzlint.py: lee tus .txt de scripts y avisa de:

  • claves que no aparecen en ningún ítem del juego (posible error de tipeo; compáralas con las de _juego/scripts/generated/items/),
  • campos que no corresponden al ItemType (por ejemplo HungerChange en un ítem que no es comida),
  • tags que no existen en el juego.

Pruébalo con mods publicados (por ejemplo, los de Wenopal). Si encuentra algo real, ya valió la pena.


Anterior: 01 · Anatomía · Siguiente: 03 · Scripts: recetas y entidades