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 adentroitem,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, noResearchableRecipes): 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 juego | Ejemplos |
|---|---|---|
base:clothing | 1.395 | ropa, mochilas que se ponen |
base:normal | 1.099 | herramientas, materiales, la lupa |
base:food | 722 | comida y bebida |
base:literature | 561 | libros, revistas, mapas de tesoro |
base:weapon | 409 | armas cuerpo a cuerpo y de fuego |
base:moveable | 393 | muebles que se recogen |
base:container | 308 | bolsos, cajas |
base:drainable | 150 | ítems con usos: estropajo, cinta, pilas |
base:radio, map, weaponpart, key, alarmclock, animal... | pocos | casos 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
| Campo | Qué hace | Detalle |
|---|---|---|
DisplayCategory | Categoría en el inventario y en el crafteo | Food, Tool, Weapon, Material... |
Weight | Peso en kg | 0.1 es liviano; un bate pesa 2.0 |
Icon | Ícono | Icon = X busca textures/Item_X.png (Tocomples Food, uno de nuestros mods, trae 161 así) |
Tags | Para qué cuenta el ítem | Lo que usan las recetas y el Lua para encontrar ítems (sección 4) |
Tooltip | Clave del texto que sale al pasar el mouse | Tooltip_CursoLab_Sopaipilla, en Translate/<IDIOMA>/Tooltip.json |
WorldStaticModel | Modelo 3D en el suelo | módulo 05 |
StaticModel | Modelo 3D en la mano | mó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 aportaEl 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 entrenaLos 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:keepacepta cualquier destornillador, incluido el tuyo si llevabase: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
- Al arrancar, Java recorre todos los
.txtdemedia/scripts/(juego + mods) y los tokeniza. - Junta los bloques por
moduley crea unItemde script por cadaitem(la plantilla). Un campo que no reconoce se ignora (a veces con un aviso enconsole.txt). - Cuando un ítem aparece en el mundo, se crea un
InventoryItem(de la clase que diceItemType) 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:
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.
- Arma una tabla con 5 armas contundentes del juego (daño, alcance, velocidad, durabilidad).
- Elige tus valores y justifica cada uno en un comentario
/* */. - 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:
- Olvida una coma al final de un campo.
- Escribe mal una clave (
Weigth = 0.5). - Pon
ItemType = base:normalen la sopaipilla. - Borra la entrada de
ItemName.json(y prueba con y sinDisplayNameen el script). - Pon un
Iconque 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 ejemploHungerChangeen 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