Beginners Custom CO Tutorial: Difference between revisions
Knightlord07 (talk | contribs) (Created page with "This is a beginners Custom CO Tutorial work") |
Knightlord07 (talk | contribs) No edit summary |
||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
This is a beginners Custom CO Tutorial work | This is a beginners Custom CO Tutorial work | ||
This is a simple tutorial for beginners, new or fresh coders to want to make their own custom CO in COW | |||
So first off you need to have this for your beginners setup.<syntaxhighlight lang="js"> | |||
var Constructor = function () { | |||
this.init = function (co, map) { | |||
co.setPowerStars(3); // This is your normal power meter | |||
co.setSuperpowerStars(3); // This is your super power meter | |||
}; | |||
this.activatePower = function(co, map) // This will use normal power (COP) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power); | |||
dialogAnimation.queueAnimation(powerNameAnimation); | |||
var units = co.getOwner().getUnits(); | |||
var animations = []; | |||
var counter = 0; | |||
units.randomize(); | |||
for (var i = 0; i < units.size(); i++) | |||
{ | |||
var unit = units.at(i); | |||
var animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY()); | |||
animation.writeDataInt32(unit.getX()); | |||
animation.writeDataInt32(unit.getY()); | |||
animation.writeDataInt32(2); | |||
animation.setEndOfAnimationCall("ANIMATION", "postAnimationHeal"); | |||
var delay = globals.randInt(135, 265); | |||
if (animations.length < 5) | |||
{ | |||
delay *= i; | |||
} | |||
animation.setSound("power0.wav", 1, delay); | |||
if (animations.length < 5) | |||
{ | |||
animation.addSprite("power0", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
powerNameAnimation.queueAnimation(animation); | |||
animations.push(animation); | |||
} | |||
else | |||
{ | |||
animation.addSprite("power0", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
animations[counter].queueAnimation(animation); | |||
animations[counter] = animation; | |||
counter++; | |||
if (counter >= animations.length) | |||
{ | |||
counter = 0; | |||
} | |||
} | |||
} | |||
units.remove(); | |||
}; | |||
this.activateSuperpower = function(co, powerMode, map) // This will use super power (SCOP) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(powerMode); | |||
powerNameAnimation.queueAnimationBefore(dialogAnimation); | |||
var units = co.getOwner().getUnits(); | |||
var animations = []; | |||
var counter = 0; | |||
units.randomize(); | |||
for (var i = 0; i < units.size(); i++) | |||
{ | |||
var unit = units.at(i); | |||
var animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY()); | |||
animation.writeDataInt32(unit.getX()); | |||
animation.writeDataInt32(unit.getY()); | |||
animation.writeDataInt32(8); | |||
animation.setEndOfAnimationCall("ANIMATION", "postAnimationHeal"); | |||
var delay = globals.randInt(135, 265); | |||
if (animations.length < 7) | |||
{ | |||
delay *= i; | |||
} | |||
if (i % 2 === 0) | |||
{ | |||
animation.setSound("power12_1.wav", 1, delay); | |||
} | |||
else | |||
{ | |||
animation.setSound("power12_2.wav", 1, delay); | |||
} | |||
if (animations.length < 7) | |||
{ | |||
animation.addSprite("power12", -map.getImageSize() * 2, -map.getImageSize() * 2, 0, 2, delay); | |||
powerNameAnimation.queueAnimation(animation); | |||
animations.push(animation); | |||
} | |||
else | |||
{ | |||
animation.addSprite("power12", -map.getImageSize() * 2, -map.getImageSize() * 2, 0, 2, delay); | |||
animations[counter].queueAnimation(animation); | |||
animations[counter] = animation; | |||
counter++; | |||
if (counter >= animations.length) | |||
{ | |||
counter = 0; | |||
} | |||
} | |||
} | |||
units.remove(); | |||
}; | |||
this.loadCOMusic = function (co, map) { | |||
// put the custom co music in here. | |||
switch (co.getPowerMode()) { | |||
case GameEnums.PowerMode_Power: | |||
audio.addMusic("mods/testco/music/cos/Power.mp3", 0, 0); | |||
break; | |||
case GameEnums.PowerMode_Superpower: | |||
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0); | |||
break; | |||
case GameEnums.PowerMode_Tagpower: | |||
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0); | |||
break; | |||
default: | |||
audio.addMusic("mods/testco/music/cos/Theme.mp3", 0, 0); | |||
break; | |||
} | |||
}; | |||
this.getCOUnitRange = function (co, map) { | |||
return Number value; //This is how much range you put in | |||
}; | |||
this.getCOArmy = function () { | |||
return "Vanilla Base Game or Custom"; //This will show up depending on which army you choose | |||
}; | |||
// CO - Intel | |||
this.getBio = function (co) { | |||
return qsTr("Type for your own description"); //Personal description | |||
}; | |||
//optional | |||
this.getLongBio = function(co, map) | |||
{ | |||
return qsTr("\n\n\"Special Message Quote\""); //Special quote description | |||
}; | |||
this.getHits = function (co) { | |||
return qsTr(""); | |||
}; | |||
this.getMiss = function (co) { | |||
return qsTr(""); | |||
}; | |||
this.getCODescription = function (co) { | |||
return qsTr("Type for your own description only affect D2D or CO zone Effect"); //Your abilities | |||
}; | |||
this.getLongCODescription = function() { | |||
return qsTr("\nD2D Effect: \nType your D2D ability") + //Your D2D ability | |||
qsTr("\n\nZone Effect: \nType your CO Zone ability"); //Your Zone ability | |||
}; | |||
this.getPowerDescription = function (co) { | |||
return qsTr("Type for your own description for power (COP)"); //COP description | |||
}; | |||
this.getPowerName = function (co) { | |||
return qsTr("Name"); //COP name | |||
}; | |||
this.getSuperPowerDescription = function (co) { | |||
return qsTr("Type for your own description for super power (SCOP)"); //SCOP description | |||
}; | |||
this.getSuperPowerName = function (co) { | |||
return qsTr("Name"); //SCOP name | |||
}; | |||
this.getPowerSentences = function (co) { | |||
switch (co.getPowerMode()) { | |||
case GameEnums.PowerMode_Power: | |||
return [qsTr("Type here for your own power quotes")]; | |||
break; | |||
case GameEnums.PowerMode_Superpower: | |||
return [qsTr("Type here for your own super power quotes")]; | |||
break; | |||
case GameEnums.PowerMode_Tagpower: | |||
return [qsTr("Type here for your own tag power quotes")]; | |||
break; | |||
} | |||
}; | |||
this.getVictorySentences = function (co) { | |||
return [qsTr("Type here for your own victory quotes")]; | |||
}; | |||
this.getDefeatSentences = function (co) { | |||
return [qsTr("Type here for your own defeat quotes")]; | |||
}; | |||
this.getName = function () { | |||
return qsTr("Name"); | |||
}; | |||
} | |||
Constructor.prototype = CO; | |||
var CO_TEST = new Constructor(); | |||
//Make sure put that CO_NAME (CO_TEST) in full caps lock in order to getting working | |||
//This is for the character alt if you add in your image folder | |||
this.getCOStyles = function() | |||
{ | |||
return ["+alt"]; | |||
}; | |||
</syntaxhighlight>Feel free to copy that code block to get started! | |||
If you got your very first setup (if you got copy it from the code block above) you good to go follow this next step! | |||
Forgot to mention about Unique unit in the base game<syntaxhighlight lang="js"> | |||
this.getCOUnits = function(co, building, map) //This allow you to have 1 unique unit in that CO buildlist | |||
{ | |||
if (CO.isActive(co)) | |||
{ | |||
var buildingId = building.getBuildingID(); | |||
if (buildingId === "FACTORY" || | |||
buildingId === "TOWN" || | |||
BUILDING.isHq(building)) | |||
{ | |||
return ["ZCOUNIT_HOT_TANK"]; | |||
} | |||
} | |||
return []; | |||
}; | |||
CO_TESTCO.getCOUnits = function(co, building, map) //This allow you swap base game unit to unique ones, the - represented remove certain unit off that CO buildlist | |||
{ | |||
if (CO.isActive(co)) | |||
{ | |||
var buildingId = building.getBuildingID(); | |||
if (buildingId === "FACTORY" || | |||
buildingId === "TOWN" || | |||
buildingId === "HQ" || | |||
buildingId === "FORTHQ") | |||
{ | |||
return ["ZCOUNIT_TANK_HUNTER", "-INFANTRY", "ZCOUNIT_ROYAL_GUARD", "-MOTORBIKE", "ZCOUNIT_AUTO_TANK", "-MECH", "ZCOUNIT_CRYSTAL_TANK", "-SNIPER", "ZCOUNIT_CHAPERON"]; | |||
} | |||
} | |||
return []; | |||
}; | |||
</syntaxhighlight> | |||
== Stats, Co zone & abilities == | |||
This is the second part of the tutorial is all about stats, CO zone & abilities | |||
Now you need some stats, just mainly your Custom Co D2D, Power & Super Power | |||
[[Modifying CO stats|Stats Code Library]] (D2D, other abilities & ects) | |||
[[Terrains|Terrain Codes]] (Modified terrain itself) | |||
[[Weather Manipulation|Weather Codes]] (Weather manipulations) | |||
[[Building]] (Props for income bonus) | |||
Units also affect on stats as well | |||
[[Naval Units|Naval]] | |||
[[Air Units|Air]] | |||
[[Infantry Units|Infantry]] | |||
[[Ground Units|Ground]] | |||
[[Hovercraft Units|Hover]] | |||
Or you could visit Github for some COs coding Resource work https://github.com/Robosturm/Commander_Wars/tree/master/resources/scripts/cos | |||
As for abilities there is quite lots cos have unique abilities | |||
* Global Damage | |||
* Reinforcements | |||
* Meteor Strike | |||
* Healing | |||
* ects | |||
For the CO zone effects you need to be like this<syntaxhighlight lang="js"> | |||
if (co.inCORange(Qt.point(defPosX, defPosY), defender)) | |||
{ | |||
return 50; | |||
} | |||
break; | |||
//Depends on which CO zone you want "Deffensive(defPosX, defPosY), defender)", "Offensive(atkPosX, atkPosY), attacker)", Luck(posX, posY), unit) | |||
</syntaxhighlight>Global Damage Codes<syntaxhighlight lang="js"> | |||
this.activatePower = function(co, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power); | |||
dialogAnimation.queueAnimation(powerNameAnimation); | |||
CO_TEST.nameDamage(co, CO_TEST.powerDamage, powerNameAnimation, map); | |||
}; | |||
this.powerDamage = 3; | |||
this.activateSuperpower = function(co, powerMode, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(powerMode); | |||
powerNameAnimation.queueAnimationBefore(dialogAnimation); | |||
CO_TEST.nameDamage(co, CO_TEST.superPowerDamage, powerNameAnimation, map); | |||
}; | |||
this.superPowerDamage = 7; | |||
this.nameDamage = function(co, value, animation2, map) | |||
{ | |||
var player = co.getOwner(); | |||
var counter = 0; | |||
var playerCounter = map.getPlayerCount(); | |||
var animation = null; | |||
var animations = []; | |||
for (var i2 = 0; i2 < playerCounter; i2++) | |||
{ | |||
var enemyPlayer = map.getPlayer(i2); | |||
if ((enemyPlayer !== player) && | |||
(player.checkAlliance(enemyPlayer) === GameEnums.Alliance_Enemy)) | |||
{ | |||
var units = enemyPlayer.getUnits(); | |||
units.randomize(); | |||
for (i = 0; i < units.size(); i++) | |||
{ | |||
var unit = units.at(i); | |||
animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY()); | |||
var delay = globals.randInt(135, 265); | |||
if (animations.length < 5) | |||
{ | |||
delay *= i; | |||
} | |||
animation.setSound("power4.wav", 1, delay); | |||
if (animations.length < 5) | |||
{ | |||
animation.addSprite("power4", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
animation2.queueAnimation(animation); | |||
animations.push(animation); | |||
} | |||
else | |||
{ | |||
animation.addSprite("power4", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
animations[counter].queueAnimation(animation); | |||
animations[counter] = animation; | |||
counter++; | |||
if (counter >= animations.length) | |||
{ | |||
counter = 0; | |||
} | |||
} | |||
animation.writeDataInt32(unit.getX()); | |||
animation.writeDataInt32(unit.getY()); | |||
animation.writeDataInt32(value); | |||
animation.setEndOfAnimationCall("ANIMATION", "postAnimationDamage"); | |||
} | |||
} | |||
} | |||
}; | |||
this.postAnimationDamage = function(postAnimation, map) | |||
{ | |||
postAnimation.seekBuffer(); | |||
var x = postAnimation.readDataInt32(); | |||
var y = postAnimation.readDataInt32(); | |||
var damage = postAnimation.readDataInt32(); | |||
if (map.onMap(x, y)) | |||
{ | |||
var unit = map.getTerrain(x, y).getUnit(); | |||
if (unit !== null) | |||
{ | |||
var hp = unit.getHpRounded(); | |||
if (hp - damage <= 0.1) | |||
{ | |||
// set hp to very very low | |||
unit.setHp(0.1); | |||
} | |||
else | |||
{ | |||
unit.setHp(hp - damage); | |||
} | |||
} | |||
} | |||
}; | |||
</syntaxhighlight>Reinforcements codes (since there are two I put them up)<syntaxhighlight lang="js"> | |||
//Sensei powers | |||
this.activatePower = function(co, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power); | |||
dialogAnimation.queueAnimation(powerNameAnimation); | |||
CO_TEST.spawnUnits(co, "INFANTRY", CO_TEST.powerSpawnHp, powerNameAnimation, map); | |||
}; | |||
this.activateSuperpower = function(co, powerMode, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(powerMode); | |||
powerNameAnimation.queueAnimationBefore(dialogAnimation); | |||
CO_TEST.spawnUnits(co, "MECH", CO_TEST.powerSpawnHp, powerNameAnimation, map); | |||
}; | |||
this.spawnUnits = function(co, unitID, hp, powerNameAnimation, map) | |||
{ | |||
var buildings = co.getOwner().getBuildings(); | |||
var animations = []; | |||
var counter = 0; | |||
buildings.randomize(); | |||
var size = buildings.size(); | |||
for (var i = 0; i < size; i++) | |||
{ | |||
var building = buildings.at(i); | |||
if (building.getBuildingID() === "TOWN") | |||
{ | |||
if (map.getTerrain(building.getX(), building.getY()).getUnit() === null) | |||
{ | |||
var animation = GameAnimationFactory.createAnimation(map, building.getX(), building.getY()); | |||
animation.writeDataInt32(building.getX()); | |||
animation.writeDataInt32(building.getY()); | |||
animation.writeDataString(unitID); | |||
animation.writeDataInt32(co.getOwner().getPlayerID()); | |||
animation.writeDataInt32(hp); | |||
animation.setStartOfAnimationCall("ANIMATION", "postAnimationSpawnUnit"); | |||
var delay = globals.randInt(135, 265); | |||
if (animations.length < 5) | |||
{ | |||
delay *= i; | |||
} | |||
if (i % 2 === 0) | |||
{ | |||
animation.setSound("power8_1.wav", 1, delay); | |||
} | |||
else | |||
{ | |||
animation.setSound("power8_2.wav", 1, delay); | |||
} | |||
if (animations.length < 5) | |||
{ | |||
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
powerNameAnimation.queueAnimation(animation); | |||
animations.push(animation); | |||
} | |||
else | |||
{ | |||
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
animations[counter].queueAnimation(animation); | |||
animations[counter] = animation; | |||
counter++; | |||
if (counter >= animations.length) | |||
{ | |||
counter = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
this.powerSpawnHp = 9; | |||
//Yukio Powers | |||
this.activatePower = function(co, map) | |||
{ | |||
var invasion = ["ARTILLERY", "FLAK", "LIGHT_TANK", "FLAK", "LIGHT_TANK"]; | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power); | |||
dialogAnimation.queueAnimation(powerNameAnimation); | |||
CO_TEST.spawnUnits(co, 0.4, invasion, powerNameAnimation, map); | |||
}; | |||
this.activateSuperpower = function(co, powerMode, map) | |||
{ | |||
var invasion = ["HEAVY_TANK", "FLAK", "LIGHT_TANK", "ARTILLERY", "LIGHT_TANK", "K_HELI", "K_HELI"]; | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(powerMode); | |||
powerNameAnimation.queueAnimationBefore(dialogAnimation); | |||
CO_TEST.spawnUnits(co, 0.7, invsion, powerNameAnimation, map); | |||
}; | |||
this.spawnUnits = function(co, count, invasion, powerNameAnimation, map) | |||
{ | |||
var buildings = co.getOwner().getBuildings(); | |||
var animations = []; | |||
var counter = 0; | |||
buildings.randomize(); | |||
var size = buildings.size(); | |||
for (var i = 0; i < size * count; i++) | |||
{ | |||
var building = buildings.at(i); | |||
if (building.getBuildingID() === "TOWN") | |||
{ | |||
if (map.getTerrain(building.getX(), building.getY()).getUnit() === null) | |||
{ | |||
var animation = GameAnimationFactory.createAnimation(map, building.getX(), building.getY()); | |||
animation.writeDataInt32(building.getX()); | |||
animation.writeDataInt32(building.getY()); | |||
animation.writeDataString(invasion[i % invasion.length]); | |||
animation.writeDataInt32(co.getOwner().getPlayerID()); | |||
animation.writeDataInt32(10); | |||
animation.setStartOfAnimationCall("ANIMATION", "postAnimationSpawnUnit"); | |||
var delay = globals.randInt(135, 265); | |||
if (animations.length < 5) | |||
{ | |||
delay *= i; | |||
} | |||
if (i % 2 === 0) | |||
{ | |||
animation.setSound("power8_1.wav", 1, delay); | |||
} | |||
else | |||
{ | |||
animation.setSound("power8_2.wav", 1, delay); | |||
} | |||
if (animations.length < 5) | |||
{ | |||
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
powerNameAnimation.queueAnimation(animation); | |||
animations.push(animation); | |||
} | |||
else | |||
{ | |||
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay); | |||
animations[counter].queueAnimation(animation); | |||
animations[counter] = animation; | |||
counter++; | |||
if (counter >= animations.length) | |||
{ | |||
counter = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
</syntaxhighlight>Meteor Code<syntaxhighlight lang="js"> | |||
this.activatePower = function(co, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power); | |||
dialogAnimation.queueAnimation(powerNameAnimation); | |||
CO_TEST.throwMeteor(co, CO_TEST.powerDamage, powerNameAnimation, map); | |||
}; | |||
this.powerDamage = 4; | |||
this.activateSuperpower = function(co, powerMode, map) | |||
{ | |||
var dialogAnimation = co.createPowerSentence(); | |||
var powerNameAnimation = co.createPowerScreen(powerMode); | |||
powerNameAnimation.queueAnimationBefore(dialogAnimation); | |||
CO_TEST.throwMeteor(co, CO_TEST.superPowerDamage, powerNameAnimation, map); | |||
}; | |||
this.superPowerDamage = 8; | |||
this.throwMeteor = function(co, damage, powerNameAnimation, map) | |||
{ | |||
var meteorTarget = co.getOwner().getRockettarget(2, damage); | |||
// create cool meteor animation :) | |||
var animation = GameAnimationFactory.createAnimation(map, meteorTarget.x + 2, meteorTarget.y - 4); | |||
animation.addSprite("meteor", 0, 0, 2500, 4.0); | |||
animation.addTweenPosition(Qt.point((meteorTarget.x - 2) * map.getImageSize(), (meteorTarget.y - 2) * map.getImageSize()), 1000); | |||
animation.addTweenScale(0.65, 1000); | |||
animation.addTweenColor(0, "#FFFFFFFF", "#00FFFFFF", 1000, false, 1200); | |||
animation.addSound("meteorFall.wav"); | |||
powerNameAnimation.queueAnimation(animation); | |||
var animation2 = GameAnimationFactory.createAnimation(map, 0, 0); | |||
animation2.addSprite2("white_pixel", 0, 0, 4200, map.getMapWidth(), map.getMapHeight()); | |||
animation2.addTweenColor(0, "#00FFFFFF", "#FFFFFFFF", 3000, true, 1000); | |||
animation2.addSound("meteorImpact.wav"); | |||
powerNameAnimation.queueAnimation(animation2); | |||
animation.setEndOfAnimationCall("CO_TEST", "postAnimationThrowMeteor"); | |||
animation.setStartOfAnimationCall("CO_TEST", "preAnimationThrowMeteor"); | |||
CO_TEST.postAnimationThrowMeteorTarget = meteorTarget; | |||
CO_TEST.postAnimationThrowMeteorDamage = damage; | |||
}; | |||
this.preAnimationThrowMeteor = function(animation, map) | |||
{ | |||
map.centerMap(CO_TEST.postAnimationThrowMeteorTarget.x, CO_STURM.postAnimationThrowMeteorTarget.y); | |||
}; | |||
this.postAnimationThrowMeteorTarget = null; | |||
this.postAnimationThrowMeteorDamage = 0; | |||
this.postAnimationThrowMeteor = function(animation, map) | |||
{ | |||
var meteorTarget = CO_TEST.postAnimationThrowMeteorTarget; | |||
var damage = CO_TEST.postAnimationThrowMeteorDamage; | |||
var fields = globals.getCircle(0, 2); | |||
// check all target fields | |||
var size = fields.size(); | |||
for (var i = 0; i < size; i++) | |||
{ | |||
var x = fields.at(i).x + meteorTarget.x; | |||
var y = fields.at(i).y + meteorTarget.y; | |||
// check if the target is on the map | |||
if (map.onMap(x, y)) | |||
{ | |||
var unit = map.getTerrain(x, y).getUnit(); | |||
if (unit !== null) | |||
{ | |||
var hp = unit.getHpRounded(); | |||
if (hp - damage <= 0.1) | |||
{ | |||
// set hp to very very low | |||
unit.setHp(0.1); | |||
} | |||
else | |||
{ | |||
unit.setHp(hp - damage); | |||
} | |||
} | |||
} | |||
} | |||
CO_TEST.postAnimationThrowMeteorTarget = null; | |||
CO_TEST.postAnimationThrowMeteorDamage = 0; | |||
}; | |||
</syntaxhighlight>If you got question about this tutorial, please visit Discord for this kind of question. | |||
== Images == | |||
The image is the next part of this tutorial. | |||
There is few thing when add some images up. | |||
First you need an res.xml file to be made first<syntaxhighlight lang="xml"> | |||
<?xml version="1.0"?> | |||
<resources> | |||
<set path = "mods/testco/images/co/" /> | |||
<atlas> | |||
<image file="co_test+nrm.png" /> | |||
<image file="co_test+info.png" /> | |||
<image file="co_test+face.png" cols = "3" /> | |||
</atlas> | |||
</resources> | |||
//Optional is if you planning make a mini please type this in <image file="co_test+mini.png" /> this allow you to see your mini when it CO board a unit in game, on the sidenote if you made an alt (skin) for your character type this in <image file="co_test+alt+nrm.png" /> (That include the info & face as well) | |||
</syntaxhighlight>So you need 3 things nrm, info & faces | |||
The nrm it can be any images size you want, here is 4 examples | |||
[[File:Co rin fate+nrm.png|none|thumb|From Knightlord07's Nasuverse mod]] | |||
Image size 308 x 557 | |||
[[File:Co landius+nrm.png|none|thumb|From Knightlord07's Langrisser vol 1 mod]] | |||
Image size 1000 x 1681 | |||
[[File:Co Wagner+alt+nrm.png|none|thumb|From Knightlord07's OCs with Under Night In-Birth Mod (This is what an alt look like)]] | |||
Image size 1024 x 1024 | |||
[[File:Co werner+nrm.png|none|thumb|From Knightlord07's Langrisser vol 2 mod]] | |||
image size is 256 x 256 | |||
If your image is big or large you can just edit the res.xml file and put this code in<syntaxhighlight lang="xml"> | |||
scale_factor = "0.55" | |||
//This allow to decrease the nrm, info & face image size in game itself | |||
</syntaxhighlight>Next is the info, the size won't matter as long it fit, recommended size is 32 x 12 but it up to you for info image size | |||
Last is the face, for your own custom co mod | |||
So here is 2 examples | |||
[[File:Co lainforce+face.png|none|thumb|This one doesn't have happy or sad (Rainforce from Langrisser Vol 3)]] | |||
[[File:Co battler+face.png|none|thumb|This one have happy & sad (Battler from Kl07's Origin Mix mod)]] | |||
So the left side is normal (netural), middle is happy & right is sad | |||
(Optional) | |||
Here is what the custom mini look like, it can be any size as long it fit the game | |||
[[File:Co liana+mini.png|none|thumb|Custom mini]] | |||
Default mini size | |||
[[File:Co brenner+mini.png|none|thumb|Default Brenner mini size]] | |||
Most of the images can be done with programs such as gimps or any other art program as long it can accept webp or any type of file image to export them into png image | |||
Be mindful about the mini image you choose you have to shrink it down a lots in order to show up the right size | |||
[[File:Co Hyde unib+mini.png|none|thumb|2D fighting game sprite that is large]] | |||
[[File:Co satsuki mb+mini.png|none|thumb|2D fighting game sprite somewhat big]] | |||
== Music == | |||
Music is another part of making custom co in order make to work<syntaxhighlight lang="js"> | |||
//Custom co music | |||
switch (co.getPowerMode()) { | |||
case GameEnums.PowerMode_Power: | |||
audio.addMusic("mods/testco/music/cos/Power.mp3", 0, 0); | |||
break; | |||
case GameEnums.PowerMode_Superpower: | |||
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0); | |||
break; | |||
case GameEnums.PowerMode_Tagpower: | |||
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0); | |||
break; | |||
default: | |||
audio.addMusic("mods/testco/music/cos/Theme.mp3", 0, 0); | |||
break; | |||
//Normal co music | |||
switch (co.getPowerMode()) { | |||
case GameEnums.PowerMode_Power: | |||
audio.addMusic("resources/music/cos/power.mp3", 992, 45321); | |||
break; | |||
case GameEnums.PowerMode_Superpower: | |||
audio.addMusic("resources/music/cos/superpower.mp3", 1505, 49515); | |||
break; | |||
case GameEnums.PowerMode_Tagpower: | |||
audio.addMusic("resources/music/cos/tagpower.mp3", 14611, 65538); | |||
break; | |||
default: | |||
audio.addMusic("resources/music/cos/andy.mp3", 4466, 74972); | |||
break; | |||
</syntaxhighlight>So in order to install custom music please follow this instruction guide | |||
(Folder) Testco (depends on what name you put it)/music/cos (That where you put your own custom music in) | |||
Once everything is sort it & done please just check your music when you enable your own mod if your custom music is working or not. | |||
== Tagpower == | |||
Tagpower is optional but you can make 2 cos SCOP combine to make strong or completely broken powers & stats | |||
Here is an example one<syntaxhighlight lang="js"> | |||
//This one is free to use | |||
TAGPOWER.TAGPOWERDATA.push(["CO_NAME", "CO_NAME", ("NAME"), NUMBER, NUMBER], //This will appear in your custom co tagpower list | |||
["CO_", "CO_", (""), , ], | |||
["CO_", "CO_", (""), , ]); | |||
//Example from Knightlord07's mods (PLEASE DO NOT COPY IT IF YOU ARE A READER!) | |||
TAGPOWER.TAGPOWERDATA.push(["CO_KNIGHTLORD07", "CO_SION_MB", ("Romance Option"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_RIESBYFE", ("New Alliance Member"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_SATSUKI_MB", ("Lover Interest"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_RIN_FATE", ("Newly Tsundere Love"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_SABER", ("Newly Master"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_CIEL", ("Dating With Senpai"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_SAKURA_FATE", ("Friendzone"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_AKIHA", ("Caring Of Love"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_TOHNO", ("Bromance"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_RYOUGI", ("Are You The Right Shiki?"), 10, 1], | |||
["CO_KNIGHTLORD07", "CO_SHIROU", ("Bro Power"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_WHITELEN", ("Kitty Tsundere"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_MIYAKO", ("Newly Onii Chan"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_NECO_ARC", ("Our Meme Lord"), 50, 5], | |||
["CO_KNIGHTLORD07", "CO_SABERLILY", ("Trust Worthly Person"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_AOKO", ("Crazy Time"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_ARCUEID", ("Fun Time"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_HISUI", ("Gamer Duo"), 50, 5], | |||
["CO_KNIGHTLORD07", "CO_KOHAKU", ("Mad Invention"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_ARCHER", ("Unlimited Meme Work"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_ASSASSIN", ("Honor Duel"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_BAZETT", ("KOF Vanessa?"), 10, 1], | |||
["CO_KNIGHTLORD07", "CO_BERSERKER", ("Madness Wrath"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_CASTER", ("Handsome Person"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_DARKSABER", ("Not Worthly Servant"), -10, 0], | |||
["CO_KNIGHTLORD07", "CO_GILGAMESH", ("Personal Lapdog"), -20, 0], | |||
["CO_KNIGHTLORD07", "CO_IIIYA", ("Let's Go Have FUN!"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_KIREI", ("Smell Traitor"), -30, 0], | |||
["CO_KNIGHTLORD07", "CO_KOUMA", ("Brawl Of Fighter"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_LANCER", ("Gamble Of Death"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_LEN", ("Here A Special Cake"), 60, 6], | |||
["CO_KNIGHTLORD07", "CO_LEYSRITT", ("Cleaning Power"), 30, 3], | |||
["CO_KNIGHTLORD07", "CO_LUVIAGELITA", ("Flirty Option"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_MICHAEL", ("Reanimated"), -20, 0], | |||
["CO_KNIGHTLORD07", "CO_NANAYA", ("Lucky Death"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_NECO_CHAOS", ("Don't Smoke In My Face"), -40, 0], | |||
["CO_KNIGHTLORD07", "CO_NRVNQSR", ("Prime Target"), -60, 0], | |||
["CO_KNIGHTLORD07", "CO_RIDER", ("New Pairs Of Glasses"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_SHINJI", ("Loser!"), -80, 0], | |||
["CO_KNIGHTLORD07", "CO_SOUICHIROU", ("Strong Fist"), 20, 2], | |||
["CO_KNIGHTLORD07", "CO_TAIGA", ("New Tiger Born"), 40, 4], | |||
["CO_KNIGHTLORD07", "CO_WALLACHIA", ("Vampire Bite"), -30, 0], | |||
["CO_KNIGHTLORD07", "CO_ZEROLANCER", ("Honor Fight"), 40, 4]); | |||
//Yeah I this is pretty much what kind of tagpower you want if you making your own tagpower | |||
</syntaxhighlight>To have a tagpower here is the instruction to make one | |||
(Folder) Testco (depends on what name you put it)/scripts/general (you need to make one) | |||
Please make tagpower.js in order to make your own tagpower | |||
[[Category:Modding_tutorials]] |
Latest revision as of 16:37, 13 August 2024
This is a beginners Custom CO Tutorial work
This is a simple tutorial for beginners, new or fresh coders to want to make their own custom CO in COW
So first off you need to have this for your beginners setup.
var Constructor = function () {
this.init = function (co, map) {
co.setPowerStars(3); // This is your normal power meter
co.setSuperpowerStars(3); // This is your super power meter
};
this.activatePower = function(co, map) // This will use normal power (COP)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
dialogAnimation.queueAnimation(powerNameAnimation);
var units = co.getOwner().getUnits();
var animations = [];
var counter = 0;
units.randomize();
for (var i = 0; i < units.size(); i++)
{
var unit = units.at(i);
var animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY());
animation.writeDataInt32(unit.getX());
animation.writeDataInt32(unit.getY());
animation.writeDataInt32(2);
animation.setEndOfAnimationCall("ANIMATION", "postAnimationHeal");
var delay = globals.randInt(135, 265);
if (animations.length < 5)
{
delay *= i;
}
animation.setSound("power0.wav", 1, delay);
if (animations.length < 5)
{
animation.addSprite("power0", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
powerNameAnimation.queueAnimation(animation);
animations.push(animation);
}
else
{
animation.addSprite("power0", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
animations[counter].queueAnimation(animation);
animations[counter] = animation;
counter++;
if (counter >= animations.length)
{
counter = 0;
}
}
}
units.remove();
};
this.activateSuperpower = function(co, powerMode, map) // This will use super power (SCOP)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(powerMode);
powerNameAnimation.queueAnimationBefore(dialogAnimation);
var units = co.getOwner().getUnits();
var animations = [];
var counter = 0;
units.randomize();
for (var i = 0; i < units.size(); i++)
{
var unit = units.at(i);
var animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY());
animation.writeDataInt32(unit.getX());
animation.writeDataInt32(unit.getY());
animation.writeDataInt32(8);
animation.setEndOfAnimationCall("ANIMATION", "postAnimationHeal");
var delay = globals.randInt(135, 265);
if (animations.length < 7)
{
delay *= i;
}
if (i % 2 === 0)
{
animation.setSound("power12_1.wav", 1, delay);
}
else
{
animation.setSound("power12_2.wav", 1, delay);
}
if (animations.length < 7)
{
animation.addSprite("power12", -map.getImageSize() * 2, -map.getImageSize() * 2, 0, 2, delay);
powerNameAnimation.queueAnimation(animation);
animations.push(animation);
}
else
{
animation.addSprite("power12", -map.getImageSize() * 2, -map.getImageSize() * 2, 0, 2, delay);
animations[counter].queueAnimation(animation);
animations[counter] = animation;
counter++;
if (counter >= animations.length)
{
counter = 0;
}
}
}
units.remove();
};
this.loadCOMusic = function (co, map) {
// put the custom co music in here.
switch (co.getPowerMode()) {
case GameEnums.PowerMode_Power:
audio.addMusic("mods/testco/music/cos/Power.mp3", 0, 0);
break;
case GameEnums.PowerMode_Superpower:
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0);
break;
case GameEnums.PowerMode_Tagpower:
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0);
break;
default:
audio.addMusic("mods/testco/music/cos/Theme.mp3", 0, 0);
break;
}
};
this.getCOUnitRange = function (co, map) {
return Number value; //This is how much range you put in
};
this.getCOArmy = function () {
return "Vanilla Base Game or Custom"; //This will show up depending on which army you choose
};
// CO - Intel
this.getBio = function (co) {
return qsTr("Type for your own description"); //Personal description
};
//optional
this.getLongBio = function(co, map)
{
return qsTr("\n\n\"Special Message Quote\""); //Special quote description
};
this.getHits = function (co) {
return qsTr("");
};
this.getMiss = function (co) {
return qsTr("");
};
this.getCODescription = function (co) {
return qsTr("Type for your own description only affect D2D or CO zone Effect"); //Your abilities
};
this.getLongCODescription = function() {
return qsTr("\nD2D Effect: \nType your D2D ability") + //Your D2D ability
qsTr("\n\nZone Effect: \nType your CO Zone ability"); //Your Zone ability
};
this.getPowerDescription = function (co) {
return qsTr("Type for your own description for power (COP)"); //COP description
};
this.getPowerName = function (co) {
return qsTr("Name"); //COP name
};
this.getSuperPowerDescription = function (co) {
return qsTr("Type for your own description for super power (SCOP)"); //SCOP description
};
this.getSuperPowerName = function (co) {
return qsTr("Name"); //SCOP name
};
this.getPowerSentences = function (co) {
switch (co.getPowerMode()) {
case GameEnums.PowerMode_Power:
return [qsTr("Type here for your own power quotes")];
break;
case GameEnums.PowerMode_Superpower:
return [qsTr("Type here for your own super power quotes")];
break;
case GameEnums.PowerMode_Tagpower:
return [qsTr("Type here for your own tag power quotes")];
break;
}
};
this.getVictorySentences = function (co) {
return [qsTr("Type here for your own victory quotes")];
};
this.getDefeatSentences = function (co) {
return [qsTr("Type here for your own defeat quotes")];
};
this.getName = function () {
return qsTr("Name");
};
}
Constructor.prototype = CO;
var CO_TEST = new Constructor();
//Make sure put that CO_NAME (CO_TEST) in full caps lock in order to getting working
//This is for the character alt if you add in your image folder
this.getCOStyles = function()
{
return ["+alt"];
};
Feel free to copy that code block to get started!
If you got your very first setup (if you got copy it from the code block above) you good to go follow this next step!
Forgot to mention about Unique unit in the base game
this.getCOUnits = function(co, building, map) //This allow you to have 1 unique unit in that CO buildlist
{
if (CO.isActive(co))
{
var buildingId = building.getBuildingID();
if (buildingId === "FACTORY" ||
buildingId === "TOWN" ||
BUILDING.isHq(building))
{
return ["ZCOUNIT_HOT_TANK"];
}
}
return [];
};
CO_TESTCO.getCOUnits = function(co, building, map) //This allow you swap base game unit to unique ones, the - represented remove certain unit off that CO buildlist
{
if (CO.isActive(co))
{
var buildingId = building.getBuildingID();
if (buildingId === "FACTORY" ||
buildingId === "TOWN" ||
buildingId === "HQ" ||
buildingId === "FORTHQ")
{
return ["ZCOUNIT_TANK_HUNTER", "-INFANTRY", "ZCOUNIT_ROYAL_GUARD", "-MOTORBIKE", "ZCOUNIT_AUTO_TANK", "-MECH", "ZCOUNIT_CRYSTAL_TANK", "-SNIPER", "ZCOUNIT_CHAPERON"];
}
}
return [];
};
Stats, Co zone & abilities
This is the second part of the tutorial is all about stats, CO zone & abilities
Now you need some stats, just mainly your Custom Co D2D, Power & Super Power
Stats Code Library (D2D, other abilities & ects)
Terrain Codes (Modified terrain itself)
Weather Codes (Weather manipulations)
Building (Props for income bonus)
Units also affect on stats as well
Or you could visit Github for some COs coding Resource work https://github.com/Robosturm/Commander_Wars/tree/master/resources/scripts/cos
As for abilities there is quite lots cos have unique abilities
- Global Damage
- Reinforcements
- Meteor Strike
- Healing
- ects
For the CO zone effects you need to be like this
if (co.inCORange(Qt.point(defPosX, defPosY), defender))
{
return 50;
}
break;
//Depends on which CO zone you want "Deffensive(defPosX, defPosY), defender)", "Offensive(atkPosX, atkPosY), attacker)", Luck(posX, posY), unit)
Global Damage Codes
this.activatePower = function(co, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
dialogAnimation.queueAnimation(powerNameAnimation);
CO_TEST.nameDamage(co, CO_TEST.powerDamage, powerNameAnimation, map);
};
this.powerDamage = 3;
this.activateSuperpower = function(co, powerMode, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(powerMode);
powerNameAnimation.queueAnimationBefore(dialogAnimation);
CO_TEST.nameDamage(co, CO_TEST.superPowerDamage, powerNameAnimation, map);
};
this.superPowerDamage = 7;
this.nameDamage = function(co, value, animation2, map)
{
var player = co.getOwner();
var counter = 0;
var playerCounter = map.getPlayerCount();
var animation = null;
var animations = [];
for (var i2 = 0; i2 < playerCounter; i2++)
{
var enemyPlayer = map.getPlayer(i2);
if ((enemyPlayer !== player) &&
(player.checkAlliance(enemyPlayer) === GameEnums.Alliance_Enemy))
{
var units = enemyPlayer.getUnits();
units.randomize();
for (i = 0; i < units.size(); i++)
{
var unit = units.at(i);
animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY());
var delay = globals.randInt(135, 265);
if (animations.length < 5)
{
delay *= i;
}
animation.setSound("power4.wav", 1, delay);
if (animations.length < 5)
{
animation.addSprite("power4", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
animation2.queueAnimation(animation);
animations.push(animation);
}
else
{
animation.addSprite("power4", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
animations[counter].queueAnimation(animation);
animations[counter] = animation;
counter++;
if (counter >= animations.length)
{
counter = 0;
}
}
animation.writeDataInt32(unit.getX());
animation.writeDataInt32(unit.getY());
animation.writeDataInt32(value);
animation.setEndOfAnimationCall("ANIMATION", "postAnimationDamage");
}
}
}
};
this.postAnimationDamage = function(postAnimation, map)
{
postAnimation.seekBuffer();
var x = postAnimation.readDataInt32();
var y = postAnimation.readDataInt32();
var damage = postAnimation.readDataInt32();
if (map.onMap(x, y))
{
var unit = map.getTerrain(x, y).getUnit();
if (unit !== null)
{
var hp = unit.getHpRounded();
if (hp - damage <= 0.1)
{
// set hp to very very low
unit.setHp(0.1);
}
else
{
unit.setHp(hp - damage);
}
}
}
};
Reinforcements codes (since there are two I put them up)
//Sensei powers
this.activatePower = function(co, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
dialogAnimation.queueAnimation(powerNameAnimation);
CO_TEST.spawnUnits(co, "INFANTRY", CO_TEST.powerSpawnHp, powerNameAnimation, map);
};
this.activateSuperpower = function(co, powerMode, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(powerMode);
powerNameAnimation.queueAnimationBefore(dialogAnimation);
CO_TEST.spawnUnits(co, "MECH", CO_TEST.powerSpawnHp, powerNameAnimation, map);
};
this.spawnUnits = function(co, unitID, hp, powerNameAnimation, map)
{
var buildings = co.getOwner().getBuildings();
var animations = [];
var counter = 0;
buildings.randomize();
var size = buildings.size();
for (var i = 0; i < size; i++)
{
var building = buildings.at(i);
if (building.getBuildingID() === "TOWN")
{
if (map.getTerrain(building.getX(), building.getY()).getUnit() === null)
{
var animation = GameAnimationFactory.createAnimation(map, building.getX(), building.getY());
animation.writeDataInt32(building.getX());
animation.writeDataInt32(building.getY());
animation.writeDataString(unitID);
animation.writeDataInt32(co.getOwner().getPlayerID());
animation.writeDataInt32(hp);
animation.setStartOfAnimationCall("ANIMATION", "postAnimationSpawnUnit");
var delay = globals.randInt(135, 265);
if (animations.length < 5)
{
delay *= i;
}
if (i % 2 === 0)
{
animation.setSound("power8_1.wav", 1, delay);
}
else
{
animation.setSound("power8_2.wav", 1, delay);
}
if (animations.length < 5)
{
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
powerNameAnimation.queueAnimation(animation);
animations.push(animation);
}
else
{
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
animations[counter].queueAnimation(animation);
animations[counter] = animation;
counter++;
if (counter >= animations.length)
{
counter = 0;
}
}
}
}
}
};
this.powerSpawnHp = 9;
//Yukio Powers
this.activatePower = function(co, map)
{
var invasion = ["ARTILLERY", "FLAK", "LIGHT_TANK", "FLAK", "LIGHT_TANK"];
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
dialogAnimation.queueAnimation(powerNameAnimation);
CO_TEST.spawnUnits(co, 0.4, invasion, powerNameAnimation, map);
};
this.activateSuperpower = function(co, powerMode, map)
{
var invasion = ["HEAVY_TANK", "FLAK", "LIGHT_TANK", "ARTILLERY", "LIGHT_TANK", "K_HELI", "K_HELI"];
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(powerMode);
powerNameAnimation.queueAnimationBefore(dialogAnimation);
CO_TEST.spawnUnits(co, 0.7, invsion, powerNameAnimation, map);
};
this.spawnUnits = function(co, count, invasion, powerNameAnimation, map)
{
var buildings = co.getOwner().getBuildings();
var animations = [];
var counter = 0;
buildings.randomize();
var size = buildings.size();
for (var i = 0; i < size * count; i++)
{
var building = buildings.at(i);
if (building.getBuildingID() === "TOWN")
{
if (map.getTerrain(building.getX(), building.getY()).getUnit() === null)
{
var animation = GameAnimationFactory.createAnimation(map, building.getX(), building.getY());
animation.writeDataInt32(building.getX());
animation.writeDataInt32(building.getY());
animation.writeDataString(invasion[i % invasion.length]);
animation.writeDataInt32(co.getOwner().getPlayerID());
animation.writeDataInt32(10);
animation.setStartOfAnimationCall("ANIMATION", "postAnimationSpawnUnit");
var delay = globals.randInt(135, 265);
if (animations.length < 5)
{
delay *= i;
}
if (i % 2 === 0)
{
animation.setSound("power8_1.wav", 1, delay);
}
else
{
animation.setSound("power8_2.wav", 1, delay);
}
if (animations.length < 5)
{
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
powerNameAnimation.queueAnimation(animation);
animations.push(animation);
}
else
{
animation.addSprite("power8", -map.getImageSize() * 1.27, -map.getImageSize() * 1.27, 0, 2, delay);
animations[counter].queueAnimation(animation);
animations[counter] = animation;
counter++;
if (counter >= animations.length)
{
counter = 0;
}
}
}
}
}
};
Meteor Code
this.activatePower = function(co, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
dialogAnimation.queueAnimation(powerNameAnimation);
CO_TEST.throwMeteor(co, CO_TEST.powerDamage, powerNameAnimation, map);
};
this.powerDamage = 4;
this.activateSuperpower = function(co, powerMode, map)
{
var dialogAnimation = co.createPowerSentence();
var powerNameAnimation = co.createPowerScreen(powerMode);
powerNameAnimation.queueAnimationBefore(dialogAnimation);
CO_TEST.throwMeteor(co, CO_TEST.superPowerDamage, powerNameAnimation, map);
};
this.superPowerDamage = 8;
this.throwMeteor = function(co, damage, powerNameAnimation, map)
{
var meteorTarget = co.getOwner().getRockettarget(2, damage);
// create cool meteor animation :)
var animation = GameAnimationFactory.createAnimation(map, meteorTarget.x + 2, meteorTarget.y - 4);
animation.addSprite("meteor", 0, 0, 2500, 4.0);
animation.addTweenPosition(Qt.point((meteorTarget.x - 2) * map.getImageSize(), (meteorTarget.y - 2) * map.getImageSize()), 1000);
animation.addTweenScale(0.65, 1000);
animation.addTweenColor(0, "#FFFFFFFF", "#00FFFFFF", 1000, false, 1200);
animation.addSound("meteorFall.wav");
powerNameAnimation.queueAnimation(animation);
var animation2 = GameAnimationFactory.createAnimation(map, 0, 0);
animation2.addSprite2("white_pixel", 0, 0, 4200, map.getMapWidth(), map.getMapHeight());
animation2.addTweenColor(0, "#00FFFFFF", "#FFFFFFFF", 3000, true, 1000);
animation2.addSound("meteorImpact.wav");
powerNameAnimation.queueAnimation(animation2);
animation.setEndOfAnimationCall("CO_TEST", "postAnimationThrowMeteor");
animation.setStartOfAnimationCall("CO_TEST", "preAnimationThrowMeteor");
CO_TEST.postAnimationThrowMeteorTarget = meteorTarget;
CO_TEST.postAnimationThrowMeteorDamage = damage;
};
this.preAnimationThrowMeteor = function(animation, map)
{
map.centerMap(CO_TEST.postAnimationThrowMeteorTarget.x, CO_STURM.postAnimationThrowMeteorTarget.y);
};
this.postAnimationThrowMeteorTarget = null;
this.postAnimationThrowMeteorDamage = 0;
this.postAnimationThrowMeteor = function(animation, map)
{
var meteorTarget = CO_TEST.postAnimationThrowMeteorTarget;
var damage = CO_TEST.postAnimationThrowMeteorDamage;
var fields = globals.getCircle(0, 2);
// check all target fields
var size = fields.size();
for (var i = 0; i < size; i++)
{
var x = fields.at(i).x + meteorTarget.x;
var y = fields.at(i).y + meteorTarget.y;
// check if the target is on the map
if (map.onMap(x, y))
{
var unit = map.getTerrain(x, y).getUnit();
if (unit !== null)
{
var hp = unit.getHpRounded();
if (hp - damage <= 0.1)
{
// set hp to very very low
unit.setHp(0.1);
}
else
{
unit.setHp(hp - damage);
}
}
}
}
CO_TEST.postAnimationThrowMeteorTarget = null;
CO_TEST.postAnimationThrowMeteorDamage = 0;
};
If you got question about this tutorial, please visit Discord for this kind of question.
Images
The image is the next part of this tutorial.
There is few thing when add some images up.
First you need an res.xml file to be made first
<?xml version="1.0"?>
<resources>
<set path = "mods/testco/images/co/" />
<atlas>
<image file="co_test+nrm.png" />
<image file="co_test+info.png" />
<image file="co_test+face.png" cols = "3" />
</atlas>
</resources>
//Optional is if you planning make a mini please type this in <image file="co_test+mini.png" /> this allow you to see your mini when it CO board a unit in game, on the sidenote if you made an alt (skin) for your character type this in <image file="co_test+alt+nrm.png" /> (That include the info & face as well)
So you need 3 things nrm, info & faces
The nrm it can be any images size you want, here is 4 examples
Image size 308 x 557
Image size 1000 x 1681
Image size 1024 x 1024
image size is 256 x 256
If your image is big or large you can just edit the res.xml file and put this code in
scale_factor = "0.55"
//This allow to decrease the nrm, info & face image size in game itself
Next is the info, the size won't matter as long it fit, recommended size is 32 x 12 but it up to you for info image size
Last is the face, for your own custom co mod
So here is 2 examples
So the left side is normal (netural), middle is happy & right is sad
(Optional)
Here is what the custom mini look like, it can be any size as long it fit the game
Default mini size
Most of the images can be done with programs such as gimps or any other art program as long it can accept webp or any type of file image to export them into png image
Be mindful about the mini image you choose you have to shrink it down a lots in order to show up the right size
Music
Music is another part of making custom co in order make to work
//Custom co music
switch (co.getPowerMode()) {
case GameEnums.PowerMode_Power:
audio.addMusic("mods/testco/music/cos/Power.mp3", 0, 0);
break;
case GameEnums.PowerMode_Superpower:
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0);
break;
case GameEnums.PowerMode_Tagpower:
audio.addMusic("mods/testco/music/cos/Super.mp3", 0, 0);
break;
default:
audio.addMusic("mods/testco/music/cos/Theme.mp3", 0, 0);
break;
//Normal co music
switch (co.getPowerMode()) {
case GameEnums.PowerMode_Power:
audio.addMusic("resources/music/cos/power.mp3", 992, 45321);
break;
case GameEnums.PowerMode_Superpower:
audio.addMusic("resources/music/cos/superpower.mp3", 1505, 49515);
break;
case GameEnums.PowerMode_Tagpower:
audio.addMusic("resources/music/cos/tagpower.mp3", 14611, 65538);
break;
default:
audio.addMusic("resources/music/cos/andy.mp3", 4466, 74972);
break;
So in order to install custom music please follow this instruction guide
(Folder) Testco (depends on what name you put it)/music/cos (That where you put your own custom music in)
Once everything is sort it & done please just check your music when you enable your own mod if your custom music is working or not.
Tagpower
Tagpower is optional but you can make 2 cos SCOP combine to make strong or completely broken powers & stats
Here is an example one
//This one is free to use
TAGPOWER.TAGPOWERDATA.push(["CO_NAME", "CO_NAME", ("NAME"), NUMBER, NUMBER], //This will appear in your custom co tagpower list
["CO_", "CO_", (""), , ],
["CO_", "CO_", (""), , ]);
//Example from Knightlord07's mods (PLEASE DO NOT COPY IT IF YOU ARE A READER!)
TAGPOWER.TAGPOWERDATA.push(["CO_KNIGHTLORD07", "CO_SION_MB", ("Romance Option"), 30, 3],
["CO_KNIGHTLORD07", "CO_RIESBYFE", ("New Alliance Member"), 40, 4],
["CO_KNIGHTLORD07", "CO_SATSUKI_MB", ("Lover Interest"), 40, 4],
["CO_KNIGHTLORD07", "CO_RIN_FATE", ("Newly Tsundere Love"), 30, 3],
["CO_KNIGHTLORD07", "CO_SABER", ("Newly Master"), 30, 3],
["CO_KNIGHTLORD07", "CO_CIEL", ("Dating With Senpai"), 30, 3],
["CO_KNIGHTLORD07", "CO_SAKURA_FATE", ("Friendzone"), 20, 2],
["CO_KNIGHTLORD07", "CO_AKIHA", ("Caring Of Love"), 30, 3],
["CO_KNIGHTLORD07", "CO_TOHNO", ("Bromance"), 30, 3],
["CO_KNIGHTLORD07", "CO_RYOUGI", ("Are You The Right Shiki?"), 10, 1],
["CO_KNIGHTLORD07", "CO_SHIROU", ("Bro Power"), 30, 3],
["CO_KNIGHTLORD07", "CO_WHITELEN", ("Kitty Tsundere"), 20, 2],
["CO_KNIGHTLORD07", "CO_MIYAKO", ("Newly Onii Chan"), 40, 4],
["CO_KNIGHTLORD07", "CO_NECO_ARC", ("Our Meme Lord"), 50, 5],
["CO_KNIGHTLORD07", "CO_SABERLILY", ("Trust Worthly Person"), 20, 2],
["CO_KNIGHTLORD07", "CO_AOKO", ("Crazy Time"), 40, 4],
["CO_KNIGHTLORD07", "CO_ARCUEID", ("Fun Time"), 30, 3],
["CO_KNIGHTLORD07", "CO_HISUI", ("Gamer Duo"), 50, 5],
["CO_KNIGHTLORD07", "CO_KOHAKU", ("Mad Invention"), 40, 4],
["CO_KNIGHTLORD07", "CO_ARCHER", ("Unlimited Meme Work"), 20, 2],
["CO_KNIGHTLORD07", "CO_ASSASSIN", ("Honor Duel"), 20, 2],
["CO_KNIGHTLORD07", "CO_BAZETT", ("KOF Vanessa?"), 10, 1],
["CO_KNIGHTLORD07", "CO_BERSERKER", ("Madness Wrath"), 30, 3],
["CO_KNIGHTLORD07", "CO_CASTER", ("Handsome Person"), 20, 2],
["CO_KNIGHTLORD07", "CO_DARKSABER", ("Not Worthly Servant"), -10, 0],
["CO_KNIGHTLORD07", "CO_GILGAMESH", ("Personal Lapdog"), -20, 0],
["CO_KNIGHTLORD07", "CO_IIIYA", ("Let's Go Have FUN!"), 30, 3],
["CO_KNIGHTLORD07", "CO_KIREI", ("Smell Traitor"), -30, 0],
["CO_KNIGHTLORD07", "CO_KOUMA", ("Brawl Of Fighter"), 20, 2],
["CO_KNIGHTLORD07", "CO_LANCER", ("Gamble Of Death"), 40, 4],
["CO_KNIGHTLORD07", "CO_LEN", ("Here A Special Cake"), 60, 6],
["CO_KNIGHTLORD07", "CO_LEYSRITT", ("Cleaning Power"), 30, 3],
["CO_KNIGHTLORD07", "CO_LUVIAGELITA", ("Flirty Option"), 40, 4],
["CO_KNIGHTLORD07", "CO_MICHAEL", ("Reanimated"), -20, 0],
["CO_KNIGHTLORD07", "CO_NANAYA", ("Lucky Death"), 20, 2],
["CO_KNIGHTLORD07", "CO_NECO_CHAOS", ("Don't Smoke In My Face"), -40, 0],
["CO_KNIGHTLORD07", "CO_NRVNQSR", ("Prime Target"), -60, 0],
["CO_KNIGHTLORD07", "CO_RIDER", ("New Pairs Of Glasses"), 20, 2],
["CO_KNIGHTLORD07", "CO_SHINJI", ("Loser!"), -80, 0],
["CO_KNIGHTLORD07", "CO_SOUICHIROU", ("Strong Fist"), 20, 2],
["CO_KNIGHTLORD07", "CO_TAIGA", ("New Tiger Born"), 40, 4],
["CO_KNIGHTLORD07", "CO_WALLACHIA", ("Vampire Bite"), -30, 0],
["CO_KNIGHTLORD07", "CO_ZEROLANCER", ("Honor Fight"), 40, 4]);
//Yeah I this is pretty much what kind of tagpower you want if you making your own tagpower
To have a tagpower here is the instruction to make one
(Folder) Testco (depends on what name you put it)/scripts/general (you need to make one)
Please make tagpower.js in order to make your own tagpower