Skip to content

Commit

Permalink
feat: 🐏Add [Questing Ram] building mechanic
Browse files Browse the repository at this point in the history
Now you can build Questing Ram just like Vanilla golem!

https://i.imgur.com/MFD9MSy.gif
  • Loading branch information
Krutoy242 committed Mar 18, 2024
1 parent 4c3bde4 commit 767b1e3
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 20 deletions.
26 changes: 26 additions & 0 deletions config/compactmachines3/recipes/twilightforest_quest_ram.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "compactmachines3:twilightforest_quest_ram",

"target-item": "minecraft:spawn_egg",
"target-nbt": "{EntityTag:{id:\"twilightforest:quest_ram\"}}",

"catalyst": "minecraft:spawn_egg",
"catalyst-nbt": "{EntityTag:{id:\"twilightforest:quest_ram\"}}",

"input-types": {
"c": { "id": "twilightforest:cicada", "ignore-meta": true },
"w": { "id": "contenttweaker:compressed_string", "ignore-meta": true },
"x": { "id": "contenttweaker:conglomerate_of_life", "ignore-meta": true }
},
"shape": [
[
["c", "w", "_", "_"]
],
[
["_", "x", "w", "w"]
],
[
["_", "w", "_", "w"]
]
]
}
20 changes: 11 additions & 9 deletions config/ftbquests/normal/chapters/4f0e4205/6d0ea21a.snbt
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
{
title: "{q.twilight_forest.spawn_questing_ram.name}",
x: 1.4d,
y: -0.4d,
text: [
"{q.twilight_forest.morb_entity_twilig.desc}"
"{q.twilight_forest.spawn_questing_ram.desc}"
],
dependencies: [
"b42dc050"
],
dependency_requirement: "one_started",
size: 0.5d,
tasks: [{
uid: "f72f1182",
type: "item",
items: [{
id: "thermalexpansion:morb",
uid: "b6a5c668",
type: "checkmark",
icon: {
id: "minecraft:spawn_egg",
tag: {
id: "twilightforest:quest_ram"
EntityTag: {
id: "twilightforest:quest_ram"
}
}
}],
ignore_damage: true,
ignore_nbt: 1b
},
disable_toast: true
}],
rewards: [{
uid: "0fcab2df",
Expand Down
3 changes: 2 additions & 1 deletion resources/ftbquests/lang/en_us.lang
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ q.twilight_forest.enter_the_twilight.name=Enter the Twilight Forest
q.twilight_forest.enter_the_twilight.desc=The Twilight Forest realm is an endless world like any other Minecraft dimension, except this dimension is densely forested.\nCraft and activate Empty Magic Map.\n\n§aHint:§r\n§7Re-enter the local world/server to fix the achievements if you are not allowed to enter new territories although you should.§r
q.twilight_forest.questing_ram.name=Questing Ram
q.twilight_forest.questing_ram.desc=The Questing Ram is a friendly boss.\n\nUnlike other bosses, this animal is §2not meant to be slain§r. Instead, the player is supposed to complete their Quest by giving it §nWool§r in every color.
q.twilight_forest.morb_entity_twilig.desc=You can spawn Questing Ram by crafting its Morb.\n\n(Any morb will finish this quest)
q.twilight_forest.spawn_questing_ram.name=Spawn Questing Ram
q.twilight_forest.spawn_questing_ram.desc=Spawn the §3Questing Ram§r by constructing a small structure, similar to how you would spawn Minecraft's Golems. Look up the §bSpawn Questing Ram§r Egg to view the recipe inside a Compact Machine.\n\n§8Note: The recipe in the Compact Machine is non-functional and is only for preview purposes.§r
q.twilight_forest.the_naga.name=The Naga
q.twilight_forest.the_naga.desc=The Naga can be found in a courtyard adorned with a snake motif. There are very few obstacles in the Courtyard, and the Naga can just as easily break them down.\nKilling the Naga and touching one of his magical scales will allow you to enter the next area.
q.twilight_forest.twilight_without_t.name=Twilight without Twilight
Expand Down
3 changes: 2 additions & 1 deletion resources/ftbquests/lang/ru_ru.lang
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ q.twilight_forest.enter_the_twilight.name=Войдите в Сумеречный
q.twilight_forest.enter_the_twilight.desc=Царство Сумеречного леса - бесконечный мир, как и любое другое измерение Minecraft, за исключением того, что это измерение густо засажено деревьями.\nCraft и активируйте Пустую магическую карту.\n\n§8Перезайдите в локальный мир / сервер что бы починить достижения, если вас не пускает на новые территории хотя должно.§r
q.twilight_forest.questing_ram.name=В поисках барана
q.twilight_forest.questing_ram.desc=Крестовый Баран — дружелюбный босс.\n\nВ отличие от других боссов, это животное §2не предназначено для убийства§r. Вместо этого игрок должен выполнить свой квест и дать ему §nШерсть§r всех цветов.
q.twilight_forest.morb_entity_twilig.desc=Вы можете породить квестового барана, создав его морба.\n\n(Любой морб завершит этот квест)
q.twilight_forest.spawn_questing_ram.name=Призвать §3Квестового Барана§r
q.twilight_forest.spawn_questing_ram.desc=Вы можете призвать §3Квестового Барана§r, построив небольшую конструкцию, аналогично призыву големов в Minecraft. Поищите §bЯйцо Призыва Квестового Барана§r, чтобы увидеть рецепт в Компактной Машине.\n\n§8Обратите внимание: рецепт в Компактной Машине не функционирует и предназначен только для предварительного просмотра.§r
q.twilight_forest.the_naga.name=Нага
q.twilight_forest.the_naga.desc=Нага можно найти во дворе, украшенном змеиным мотивом. Во дворе очень мало препятствий, и нага может легко их сломать.\nУбив нага и прикоснувшись к одной из его волшебных чешуек, вы попадете в следующую область.
q.twilight_forest.twilight_without_t.name=Сумерки без Сумерек
Expand Down
3 changes: 2 additions & 1 deletion resources/ftbquests/lang/zh_cn.lang
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ q.twilight_forest.enter_the_twilight.name=进入暮色森林
q.twilight_forest.enter_the_twilight.desc=暮色森林,就和其他维度一样,是个无尽的世界,不过这个维度几乎全部被森林覆盖。\n合成并激活魔法地图。\n\n§7如果不允许您进入新领地,但您应该重新进入本地世界/服务器来修复成就。§r
q.twilight_forest.questing_ram.name=迷题羊
q.twilight_forest.questing_ram.desc=迷题羊是个友善的boss。\n\n不像其他boss,你§2不需要§r伤害它。只要给它所有颜色的§n羊毛§r,就能完成它的谜题。
q.twilight_forest.morb_entity_twilig.desc=你可以通过制作公羊的变形来产生任务公羊。(任何变形都可以完成这个任务)
q.twilight_forest.spawn_questing_ram.name=任务之羊
q.twilight_forest.spawn_questing_ram.desc=您可以通过建造一个小型结构来召唤 §3任务之羊§r,类似于召唤Minecraft中的傀儡。查询 §b召唤任务之羊§r 蛋以在紧凑机器内查看配方。\n\n§8注意:紧凑机器中的配方是不可用的,仅供预览之用。§r
q.twilight_forest.the_naga.name=娜迦
q.twilight_forest.the_naga.desc=娜迦能在一个蛇形装饰的庭院中找到。庭院中几乎没有障碍,娜迦能轻易破坏很多方块。\n杀死娜迦并触碰到它的魔法鳞片使你能进入下一区域。
q.twilight_forest.twilight_without_t.name=无光之暮色
Expand Down
10 changes: 8 additions & 2 deletions scripts/cot/functions.zs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ val lifeRecipes = {
'minecraft:ocelot' : { <actuallyadditions:item_hairy_ball>: 4 },
} as int[IItemStack][string];

<cotBlock:conglomerate_of_life>.onBlockPlace = function (world, p, blockState) { createParticles(world, p); };
<cotBlock:conglomerate_of_life>.onBlockPlace = function (world, p, blockState) {
if (!world.remote) scripts.do.build_mob.build(world, p, blockState);
createParticles(world, p);
};
<cotBlock:conglomerate_of_life>.onBlockBreak = function (world, p, blockState) { createParticles(world, p); };
<cotBlock:conglomerate_of_life>.onRandomTick = function (world, p, blockState) {
if (world.remote) return;
Expand All @@ -68,7 +71,10 @@ val lifeRecipes = {
}
};

<cotBlock:conglomerate_of_sun>.onBlockPlace = function (world, p, blockState) { createParticles(world, p, 10, 'endRod'); };
<cotBlock:conglomerate_of_sun>.onBlockPlace = function (world, p, blockState) {
if (!world.remote) scripts.do.build_mob.build(world, p, blockState);
createParticles(world, p, 10, 'endRod');
};
<cotBlock:conglomerate_of_sun>.onBlockBreak = function (world, p, blockState) { createParticles(world, p, 10, 'endRod'); };
<cotBlock:conglomerate_of_sun>.onRandomTick = function (world, p, blockState) {
if (world.remote) return;
Expand Down
2 changes: 2 additions & 0 deletions scripts/debug/devtools.zs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#modloaded ctintegration draconicevolution
#reloadable

#priority 3999

import crafttweaker.block.IBlock;
import crafttweaker.block.IBlockState;
import crafttweaker.data.IData;
Expand Down
190 changes: 190 additions & 0 deletions scripts/do/build_mob.zs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* @file API for adding Golem-like mob spawning mechanics bu building structures
*
* @author Krutoy242
* @link https://github.com/Krutoy242
*/

// Zenutils required to run late CoT function and use <cotBlock:> bracket handlers
#modloaded zenutils

// Need to be set between Utils and build_mob.add() users
#priority 2000
#reloadable

import crafttweaker.block.IBlockState;
import crafttweaker.entity.IEntityDefinition;
import crafttweaker.item.IItemStack;
import crafttweaker.util.Position3f;
import crafttweaker.block.IBlock;
import crafttweaker.world.IBlockPos;
import crafttweaker.world.IWorld;

zenClass MobBuild {
// Static data
var entity as IEntityDefinition;
var volume as string[][];
var map as IItemStack[string];
var spawnFnc as function(IWorld,IBlockPos)void;

// Computed fields
var core as IItemStack;
var coreX as int = 0;
var coreY as int = 0;
var coreZ as int = 0;
var center as Position3f;

zenConstructor() { }

function getCore() as IItemStack {
if (!isNull(core)) return core;

for y, yLayer in volume {
if (!isNull(core)) break;

for x, zLine in yLayer {
if (!isNull(core)) break;

for z in 0 .. zLine.length() {
val c = zLine[z];
if (c == ' ') continue;
val block = map[c];
if (isNull(block)) {
logger.logWarning('Wrong item map for char "' ~ c ~ '" in MobBuild ' ~ entity.name);
continue;
}
if (c != 'x') continue;
core = block;
coreX = x;
coreY = y;
coreZ = z;
break;
}
}
}

if (isNull(core)) {
logger.logWarning('Cannot find core (letter "x") for MobBuild ' ~ entity.name);
}
return core;
}

function iterVolume(pos as IBlockPos, face as int, func as function(IItemStack,IBlockPos)bool) as bool {
for y, yLayer in volume {
for x, zLine in yLayer {
for z in 0 .. zLine.length() {
val c = zLine[z];
if (c == ' ') continue;
val r = rotate(face, x - coreX, z - coreZ);
val p = IBlockPos.create(
pos.x + r[0],
pos.y + volume.length - 1 - y - coreY,
pos.z + r[1]
);
if (func(map[c], p)) continue;
return false;
}
}
}
return true;
}

function make(world as IWorld, pos as IBlockPos) as bool {
val offset = getCenter();
for face in 0 .. 4 {
// Check if we have all blocks on place
if (!iterVolume(pos, face, function (need as IItemStack, p as IBlockPos) as bool {
val state = world.getBlockState(p);
val haveItem = state.block.getItem(world, p, state);
return need has haveItem;
})) continue;

// Break blocks and spawn entity
iterVolume(pos, face, function (need as IItemStack, p as IBlockPos) as bool {
world.destroyBlock(p, false);
utils.spawnParticles(world, 'snowballpoof', 0.5 + p.x, 0.5 + p.y, 0.5 + p.z, 0.5, 0.5, 0.5, 0, 10);
return true;
});

val r = rotate(face, offset.x, offset.z);
val truePos = Position3f.create(r[0] + pos.x, offset.y + pos.y - 1.5f, r[1] + pos.z);
utils.executeCommandSilent(server, '/summon ' ~ entity.id ~ ' ' ~ truePos.x ~ ' ' ~ truePos.y ~ ' ' ~ truePos.z ~ ' {Rotation:[' ~ (face * 90 - 180) ~ 'f,0f]}');

spawnFnc(world, pos);

return true;
}
return false;
}

function getCenter() as Position3f {
if (isNull(center)) center = Position3f.create(
0.5f * volume[0].length - coreX,
0.5f * volume.length - coreY,
0.5f * volume[0][0].length() - coreZ
);

return center;
}

function rotate(face as int, x as float, z as float) as float[] {
return [
face == 0 ? x : face == 1 ? -z : face == 2 ? -x : z,
face == 0 ? z : face == 1 ? x : face == 2 ? -z : -x,
];
}
}

static builds as MobBuild[IEntityDefinition] = {} as MobBuild[IEntityDefinition];

function add(entity as IEntityDefinition, volume as string[][], map as IItemStack[string], spawnFnc as function(IWorld,IBlockPos)void = null) as void {
val m = MobBuild();
m.entity = entity;
m.volume = volume;
m.map = map;
m.spawnFnc = spawnFnc;
builds[entity] = m;

if (utils.DEBUG) {
var s = '';
s ~= '\n"input-types": {\n';
var k = 0;
for c, item in map {
val block = item.asBlock();
s ~= (k == 0 ? '' : ',\n') ~ ' "' ~ c ~ '": { "id": "' ~ block.definition.id ~ '", "ignore-meta": true }';
k += 1;
}
s ~= '\n},\n"shape": [';
for i, plane in volume {
s ~= (i == 0 ? '' : '\n ],') ~ '\n [\n';
for j, line in plane {
val l = line.replaceAll(' ', '_').replaceAll('.', '"$0", ');
s ~= (j == 0 ? '' : ',\n') ~ ' [' ~ l.substring(0, l.length() - 2) ~ ']';
}
}
s ~= '\n ]\n]';

val fileName = entity.id.replaceAll(':', '_');
utils.log('Added Build Mob recipe for file config/compactmachines3/recipes/' ~ fileName ~ '.json'
~ '\n{'
~ '\n "name": "compactmachines3:' ~ fileName ~ '",'
~ '\n'
~ '\n "target-item": "minecraft:spawn_egg",'
~ '\n "target-nbt": "{EntityTag:{id:\\"' ~ entity.id ~ '\\"}}",'
~ '\n'
~ '\n "catalyst": "minecraft:spawn_egg",'
~ '\n "catalyst-nbt": "{EntityTag:{id:\\"' ~ entity.id ~ '\\"}}",'
~ '\n'
~ ' ' ~ s.replaceAll('\n(.)', '\n $1')
~ '\n}\n'
);
}
}

function build(world as IWorld, pos as IBlockPos, state as IBlockState) as void {
for entity, build in builds {
if (!(state.block has build.getCore())) continue;

if (build.make(world, pos)) return;
}
}
6 changes: 0 additions & 6 deletions scripts/mods/scalinghealth.zs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,5 @@ for mobId, ingr in {
[h,h,h], ingr, <thermalexpansion:morb>, <fluid:water> * 50, 40);
}

// Special case for Questing Ram
mods.rustic.Condenser.addRecipe(
<thermalexpansion:morb>.withTag({ id: 'twilightforest:quest_ram' }),
[h,<ore:dustMithril>,<twilightforest:cicada>], <twilightforest:magic_map_focus>, <thermalexpansion:morb>, <fluid:water> * 50, 40
);

// Peaceful alt
mods.inworldcrafting.ExplosionCrafting.explodeBlockRecipe(<scalinghealth:crystalore>, <minecraft:redstone_ore>, 1);
16 changes: 16 additions & 0 deletions scripts/mods/twilightforest.zs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ for i, poolTuple in garanteedPools {
pool.addItemEntry(newDrops[i], 1);
}
scripts.jei.entity_drop.add(<entity:twilightforest:quest_ram>, newDrops, false);

function abs(n as double) as double { return n < 0 ? -n : n; }
scripts.do.build_mob.add(<entity:twilightforest:quest_ram>, [
['cw '],
[' xww'],
[' w w'],
], {
c: <twilightforest:cicada>,
w: <contenttweaker:compressed_string>,
x: <contenttweaker:conglomerate_of_life>,
}, function(world as crafttweaker.world.IWorld, p as crafttweaker.world.IBlockPos) as void {
for pl in world.getAllPlayers() {
if (abs(pl.x - p.x) > 20 || abs(pl.y - p.y) > 20 || abs(pl.z - p.z) > 20) continue;
pl.sendPlaySoundPacket('minecraft:entity.sheep.ambient', 'ambient', p, 1, 1);
}
});
/////////////////////////////////////////

for tuple in [
Expand Down

0 comments on commit 767b1e3

Please sign in to comment.