Linken’s Sphere: evolución, funcionamiento, errores y solución
Introducción: la evolución de Linken’s Sphere
En las primeras versiones de DotA, el objeto
Linken's Sphere (en adelante: linken, esfera) estaba basado en el
Amulet of Spell Shield (en adelante: amuleto de protección), que bloqueaba hechizos estándar. Sin embargo, pronto surgió un problema: ¿cómo distinguir las habilidades default de las custom.
Habilidades default
Están integradas en el motor de Warcraft III, por ejemplo:
Storm Bolt —
Mountain King
Slow —
Sorceress
Blizzard —
Archmage
Su funcionamiento solo puede modificarse parcheando el archivo game.dll, lo cual no es tarea sencilla.
Habilidades custom
Son creadas por los autores del mapa de DotA mediante código.
Por ejemplo, la habilidad
Magic Missile de
Vengeful Spirit es en realidad una versión modificada de
Storm Bolt (en adelante: martillo). Se puede cambiar el ícono, el proyectil, la descripción y las animaciones, pero no se puede hacer que el martillo aturda y ralentice al mismo tiempo.
La solución llegó rápidamente: usar una habilidad default como base y superponer una segunda mediante código.
Ejemplo —
Void de
Balanar.
- El daño y el ministun lo proporciona el martillo.
- El efecto de ralentización se basa en Slow, que es lanzado por una unidad Dummy (en adelante: dummy). El dummy es una unidad invisible e invulnerable creada por código, que realiza una acción específica y luego se elimina.
El
Amuleto de Spell Shield no puede bloquear este tipo de hechizo. Como el dummy no tiene animación de lanzamiento y Slow no tiene proyectil, la ralentización se aplica primero y rompe el amuleto, y solo después llega el martillo (con velocidad 10000 y sin animación de proyectil).
La runa de Linken’s Sphere y su funcionamiento
Como el motor del juego no permite verificar si el
Amuleto de Spell Shield activo o en enfriamiento, IceFrog creó una versión custom de la
linken en una de las actualizaciones del mapa. El objeto en sí es una placeholder que no bloquea nada, pero al recogerlo, el héroe recibe la
runa Linken’s Sphere (en adelante: runa).
¿Recuerdas ese viejo bug donde la runa caía al suelo al ser entregada?
Viejo bug — la runa caía al suelo al entregarse
https://www.youtube.com/watch?v=kii4c_I1YVU
Esto ocurría si el héroe no estaba en el mapa durante la entrega (por ejemplo:
Astral Imprisonment,
Disruption,
Burrowstrike,
Supernova), o tenía el inventario bloqueado (
Meat Hook durante el lanzamiento).La runa quedaba en el suelo junto al héroe.
IceFrog solucionó parcialmente el problema con una lógica simple: si el héroe no logra recoger la runa, esta se elimina y se repite la entrega hasta que tenga éxito.
En realidad, la
runa runa está basada en otro objeto estándar:
Rune of Shielding, que otorga un escudo que bloquea un hechizo enemigo.
Su funcionamiento es similar al del amuleto, pero la diferencia clave es que aplica un buff de estado, cuya presencia puede verificarse por código.
IceFrog introdujo una función, cuyo nombre exacto se desconoce por la ofuscación del código, pero suponemos que tenía esta firma:
function IsUnitHasNegation takes unit u returns boolean
return GetUnitAbilityLevel(u, 'B0BI') > 0
or GetUnitAbilityLevel(u, 'BNss') > 0
or GetUnitAbilityLevel(u, 'B0EV') > 0
endfunction
Esta función verifica si la unidad tiene el buff de la runa ('B0BI').
Desde entonces, las habilidades custom comenzaron a verificar la presencia del buff. Si está presente, el resto del código —creación del dummy, aplicación de ralentización u otros efectos— no se ejecuta. El buff se consume, bloqueando la habilidad base.
Sin embargo, IceFrog omitió varias docenas de habilidades que no incluían esta verificación, lo que llevó a una implementación incompleta. En nuestro mapa, todas las habilidades problemáticas identificadas han sido corregidas y ahora interactúan correctamente con la linken.
Bug con Dummy y habilidades AOE
También surgieron otros problemas: algunas habilidades no apuntan a unidades, sino que se aplican en áreas.
Ejemplo —
Shrapnel de
Dwarven Sniper. Está basada en una habilidad canalizada, es decir, una placeholder a la que se puede configurar el tipo de objetivo y el área. Como la habilidad base no hace nada, todo su efecto se implementa por código.
La ralentización en Shrapnel (DotA por IceFrog) es nuevamente el mismo
Slow, aplicado por un dummy. Sin embargo, IceFrog cometió un error y asignó como dueño del dummy al propio Dwarven Sniper, en lugar del héroe que recibe la ralentización. Como resultado, el buff de la
runa se activaba y se consumía. Afortunadamente, corregimos este error.
Bug con Linken’s Sphere después de venderla
¿Te suena este bug?
https://www.youtube.com/watch?v=ORKW3tgYXgE
Está relacionado con cómo está implementada la
linken. Como está codificada en el mapa, técnicamente no refleja nada — lo que bloquea es el buff de la runa que se entrega al héroe. La animación de enfriamiento es solo una ilusión visual creada con mucho código.
Un poco de información técnica
El script del mapa incluye un ciclo que, desde el inicio del juego, se ejecuta cada 0.33 segundos. Revisa el estado de cada héroe: si está vivo, si está presente en el mapa y el valor del contador de enfriamiento de la linken.
Si el contador es mayor que 0, el héroe está vivo y presente, pero no tiene el buff de reflejo, se activa una función adicional. Esta función revisa todo el inventario, busca Linken Spheres (si hay más de una), las lanza al suelo y las elimina. Luego crea linkens falsas en el inventario de un dummy con los mismos atributos. Estas linken no tienen objetivo, no pueden usarse en aliados, y al hacer clic se van a enfriamiento. El script simula el clic, las linken entran en enfriamiento y luego se entregan al héroe.
Todo esto ocurre casi instantáneamente — el jugador no nota nada y simplemente ve la animación de enfriamiento. Mientras tanto, se crea un temporizador que espera el tiempo de enfriamiento de la
linken, o hasta que el héroe reviva (si murió durante ese tiempo), para entregar la runa y reemplazar el objeto en el inventario.
¿Por qué el buff de la
runa permanecía incluso después de vender el objeto?
La causa es un error en el código de lanzamiento y recogida de objetos. Se produce una recursión en el trigger que rastrea los contadores de linken. Con cada llamada recursiva, el contador aumenta, y el código no verifica si el héroe aún tiene la linken en su inventario — basta con que el contador sea mayor que 0.
Solución mediante una variable global
¿Por qué se necesitaban estos “parches”? No está claro. Pero encontramos la solución.
Al agregar una variable global booleana ItemBool, y verificar su valor en el trigger que reacciona a la recogida y lanzamiento de objetos, ahora:
- cambiamos el valor de la variable antes de iniciar el enfriamiento de la linken,
- lo restauramos después,
- evitamos la recursión,
- y el contador siempre refleja la cantidad real de Linken Spheres que posee el héroe.
Seamos sinceros — nadie quiere comprar más de una linken.
Conclusión
Con esto concluimos nuestro análisis de este maravilloso objeto. Hemos explorado su funcionamiento, los errores que arrastró durante años y una solución elegante. Leer todo esto es como construir una linken desde cero — y tú lo lograste 🙂
