Class Based Modification (CBM) is the community’s longest running and most notable class mod, introducing a class for just about every mainline robot master in the Mega Man series. It’s been in the works for over 10 years and has been passed between multiple groups of developers over time, making it one of the most varied modded experiences.

Custom Class Support


<aside> ⚠️ **Warning: This tutorial details extra steps that should be taken when creating a class for compatibility with CBM. It goes without saying that you should already have experience with creating classes for MM8BDM V6B itself.

It is also useful to go ahead and look at the tips for custom weapons with CBM!**

</aside>

With the release of MM8BDM V6B, as with a lot of other newer mods, CBM is now largely compatible with content expansions such as additional classes. Using CBM’s CBMADD.acs ACS library, which can be found inside of its file at acs_source/cbm_dt/CBMADD.acs, you’ll be able to follow along with this page and implement a class which is compatible with standalone MM8BDM, CBM, and even potentially the forks of CBM to come.

The class that we’ll be making as an example is Megaman X as a copy weapon class. For that reason, we’ll be using ClassBase as our class’s inherited actor and BaseMM8BDMWep as our weapons’ inherited actor. However, all the same rules as standalone MM8BDM classes apply when extending the compatibility to CBM.

Beefed Up Values


CBM is one of the community’s mods which has “beefed up” damage and HP values, meaning that it multiplies every original damage and HP value by 10. While in base MM8BDM, the default HP range is 100 and the Mega Buster deals 10 damage, in CBM, the default HP range is 1000 and the Mega Buster deals 100 damage.

It does this to enable some steeper damage and defense multipliers which would be unviable or cause unintended consequences in the standard range of values due to limitations of the Zandronum engine.

For your class, this means that you’ll need a mechanism to have normal HP and do normal damage, except when CBM’s “beefed up” values are loaded, in which case you should multiply the class’s HP and their damage by 10. We’ll discuss how to handle the HP in the next section, but for the damage, CBMADD.acs provides a helper function to help us create that mechanism. You should create a script that looks like below for your own class(es).

#library "XACS"
#include "zcommon.acs"

#include "CBMADD.acs"

script "MMX_CBM_Damage" (int dmg) {
	if(CBMBeefInPlay()) { // Checks for beefed up values
		dmg *= 10;
	}
	SetResultValue(dmg);
}

This script is fairly simple in concept, it takes in a damage value and returns back a damage value using [SetResultValue](<https://zdoom.org/wiki/SetResultValue>). If CBM’s beefed up values are loaded, it’ll return the damage given but multiplied by 10. We’ll use this script in our class’s DECORATE like below.

actor X_Shot1 : BasicProjectile
{
	damagetype "Buster"
	Obituary "$OB_XBUSTER"
	+BRIGHT
	Damage (CallACS("MMX_CBM_Damage", 10))
	radius 10
	height 5
	Speed 35
	States
	{
		Spawn:
			TNT1 A 2
			BUST A 1
			wait
		}
}

actor X_Shot2 : X_Shot1
{
	Damage (CallACS("MMX_CBM_Damage", 15))
	radius 15
	height 5
	Speed 40
	States
	{
		Spawn:
			TNT1 A 2
			X1AB JKLMN 2
			Goto Spawn+1
	}
}

actor X_Shot3 : X_Shot2
{
	Damage (CallACS("MMX_CBM_Damage", 35))
	radius 18
	height 25
	speed 40
	States
	{
		Spawn:
			TNT1 A 0
			TNT1 A 1
			X1AB ABC 2
			goto Spawn+2
	}
}

Notably, every instance where a damage value is defined, we’ve substituted it with [CallACS](<https://zdoom.org/wiki/ACS_NamedExecuteWithResult>) using our new script. If you’re experienced with regex and use a more advanced code editor (such as VSCode), you can use the below regex to find all common instances of where damage values would be specified.

(a_explode\\s*\\()|(damage((\\s*\\()|(thing)))|(core_((propexplode)|(teamexplode)|(damageowner)|(damageactor)))

Starting Inventory


In addition to dealing with the class’s starting HP, we’ve also got their starting inventory to resolve. If you recall, a class made for standalone MM8BDM should always have BaseFlagPack as a starting item. CBM has its own variant of this inventory named CBM_BaseFlagPack which adds additional behavior in addition to giving BaseFlagPack. Additionally, CBM has its copy weapon nerf actors which need to be given if you’re designing a class intended to use copy weapons.

This means for best practices, we’ll need to be able to give BaseFlagPack in standalone MM8BDM but CBM_BaseFlagPack and potentially copy weapon nerf actors whenever CBM is loaded. To accomplish this as well as the issue of starting HP. We’ll do the following:

actor MegamanXC : ClassBase
{
	Player.ScoreIcon "XMUGSHT1"
	player.displayname "MegamanX"
	player.soundclass "megamanx"

	player.maxhealth 1000
	health 1000
	player.jumpz 10
	player.forwardmove 0.8, 0.8
	player.sidemove 0.78, 0.78

	player.startitem "X_StartingInventory"
	...
}

actor X_StartingInventory : CustomInventory
{
	States
	{
		Pickup:
			TNT1 A 0 ACS_NamedExecuteWithResult("MMX_StartingInventory", true)
			stop
	}
}

We’ll first pretend that CBM is always loaded and give our class their intended HP value but multiplied by 10. Instead of giving BaseFlagPack or CBM_BaseFlagPack, we’ll actually give our own defined actor which calls an ACS script. The ACS script is defined below.

#library "XACS2"
#include "zcommon.acs"

#include "CBMADD.acs"

script "MMX_StartingInventory" (int copynerf) {
	if(!CBMBeefInPlay()) {
		SetActorProperty(0, APROP_Health, GetActorProperty(0, APROP_Health) / 10);
		SetActorProperty(0, APROP_SpawnHealth, GetActorProperty(0, APROP_SpawnHealth) / 10);
	}
	
	if(CBMInPlay()) {
		GiveInventory("CBM_BaseFlagPack", 1);
		if(copynerf) {
			GiveInventory("CopyNerfGiver_P", 1);
		}
	} else {
		GiveInventory("BaseFlagPack", 1);
	}
}