SapperLogic.as

Last-modified: 2017-05-29 (月) 15:08:12

■全体構成(「※1」などで検索して飛んでみよう)
※1
※2
※3

■内容解説

#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])
#include(): Usage: (a-page-name-you-want-to-include[,title|,notitle])

void sapper_actorlimit_setup(CBlob@ this)
{

	u16[] networkIDs;
	this.set("LimitedActors", networkIDs);

}

bool sapper_has_hit_actor(CBlob@ this, CBlob@ actor)
{

	u16[]@ networkIDs;
	this.get("LimitedActors", @networkIDs);
	return networkIDs.find(actor.getNetworkID()) >= 0;

}

u32 sapper_hit_actor_count(CBlob@ this)
{

	u16[]@ networkIDs;
	this.get("LimitedActors", @networkIDs);
	return networkIDs.length;

}

void sapper_add_actor_limit(CBlob@ this, CBlob@ actor)
{

	this.push("LimitedActors", actor.getNetworkID());

}

void sapper_clear_actor_limits(CBlob@ this)
{

	this.clear("LimitedActors");

}

void onInit(CBlob@ this)
{

	SapperInfo sapper;
	sapper.state = SapperStates::normal;
	sapper.slideTime = 0;
	sapper.tileDestructionLimiter = 0;
	this.set("sapperInfo", @sapper);
	this.set_f32("gib health", -3.0f);
	addShieldVars(this, SHIELD_BLOCK_ANGLE, 2.0f, 5.0f);
	sapper_actorlimit_setup(this);
	this.getShape().SetRotationsAllowed(false);
	this.getShape().getConsts().net_threshold_multiplier = 0.5f;
	this.Tag("player");
	this.Tag("flesh");
	this.addCommandID("get bomb");
	this.push("names to activate", "keg");
	this.set_u8("bomb type", 255);
	for (uint i = 0; i < bombTypeNames.length; i++)
	{
		this.addCommandID("pick " + bombTypeNames[i]);
	}
	//centered on bomb select   ※2
	//this.set_Vec2f("inventory offset", Vec2f(0.0f, 122.0f));
	//centered on inventory
	this.set_Vec2f("inventory offset", Vec2f(0.0f, 0.0f));
	SetHelp(this, "help self action", "sapper", "$Jab$Jab        $LMB$", "", 4);
	SetHelp(this, "help self action2", "sapper", "$Shield$Shield    $KEY_HOLD$$RMB$", "", 4);
	this.getCurrentScript().runFlags |= Script::tick_not_attached;
	this.getCurrentScript().removeIfTag = "dead";

}

void onSetPlayer(CBlob@ this, CPlayer@ player)
{

	if (player !is null)
	{
		player.SetScoreboardVars("ScoreboardIconsMod.png", 3, Vec2f(16, 16));
	} ※スコアボードに表示されるアイコン関係?

}

void onTick(CBlob@ this)
{

	u8 knocked = getKnocked(this);
	if (this.isInInventory())
		return;
	//sapper logic stuff ※3
	//get the vars to turn various other scripts on/off
	RunnerMoveVars@ moveVars;
	if (!this.get("moveVars", @moveVars))
	{
		return;
	}
	SapperInfo@ sapper;
	if (!this.get("sapperInfo", @sapper))
	{
		return;
	}
	Vec2f pos = this.getPosition();
	Vec2f vel = this.getVelocity();
	Vec2f aimpos = this.getAimPos();
	const bool inair = (!this.isOnGround() && !this.isOnLadder());
	Vec2f vec;
	const int direction = this.getAimDirection(vec);
	const f32 side = (this.isFacingLeft() ? 1.0f : -1.0f);
	bool pressed_a1 = this.isKeyPressed(key_action1) && !this.hasTag("noLMB");
	bool pressed_a2 = this.isKeyPressed(key_action2);
	bool walking = (this.isKeyPressed(key_left) || this.isKeyPressed(key_right));
	const bool myplayer = this.isMyPlayer();
	if (!this.hasTag("exploding"))
	if (pressed_a2) //Self detonate
	{
		SetupBomb(this, 120, 64.0f, 8.0f, 24.0f, 0.4f, true);
	}
	if(sapper.throwtimer == 0){
		if(sapper.cooldown == 0){
			if (this.isKeyPressed(key_action1) && !this.hasTag("noLMB"))
			{
				sapper.throwtimer = 8;
				this.Tag("throwing_mine");
				sapper.cooldown = 60;
			}
		} else {
			sapper.cooldown -= 1;
		}
	}
	if(sapper.throwtimer == 1){
		if (getNet().isServer()){
			CBlob @blob = server_CreateBlob("minimine", this.getTeamNum(), this.getPosition());
			blob.SetDamageOwnerPlayer(this.getPlayer());
			Vec2f arrowVel = ((this.getPosition() + Vec2f(0.0f, -4.0f)) - (this.getAimPos() + Vec2f(0.0f, -4.0f)));
			arrowVel.Normalize();
			arrowVel *= -6;
			blob.setVelocity(arrowVel);
		}
		this.Untag("throwing_mine");
		sapper.throwtimer -= 1;
	} else if(sapper.throwtimer != 0){
		sapper.throwtimer -= 1;
	}
	//with the code about menus and myplayer you can slash-cancel; ※4
	//we'll see if sappers dmging stuff while in menus is a real issue and go from there
	if (knocked > 0)// || myplayer && getHUD().hasMenus())
	{
		sapper.state = SapperStates::normal;
		sapper.slideTime = 0;
		pressed_a1 = false;
		pressed_a2 = false;
		walking = false;
	}
	else if (this.isKeyJustReleased(key_action2) || (this.isKeyJustReleased(key_action1) && !this.hasTag("noLMB")) || this.get_u32("sapper_timer") <= getGameTime())
	{
		sapper.state = SapperStates::normal;
	}
	//throwing bombs
	if (myplayer)
	{
		// space
		if (this.isKeyJustPressed(key_action3))
		{
			CBlob@ carried = this.getCarriedBlob();
			bool holding = carried !is null;// && carried.hasTag("exploding");
			CInventory@ inv = this.getInventory();
			bool thrown = false;
			u8 bombType = this.get_u8("bomb type");
			if (bombType == 255)
			{
				SetFirstAvailableBomb(this);
				bombType = this.get_u8("bomb type");
			}
			if (bombType < bombTypeNames.length)
			{
				for (int i = 0; i < inv.getItemsCount(); i++)
				{
					CBlob@ item = inv.getItem(i);
					const string itemname = item.getName();
					if (!holding && bombTypeNames[bombType] == itemname)
					{
						if (bombType >= 2)
						{
							this.server_Pickup(item);
							client_SendThrowOrActivateCommand(this);
							thrown = true;
						}
						else
						{
							CBitStream params;
							params.write_u8(bombType);
							this.SendCommand(this.getCommandID("get bomb"), params);
							thrown = true;
						}
						break;
					}
				}
			}
			if (!thrown)
			{
				client_SendThrowOrActivateCommand(this);
				SetFirstAvailableBomb(this);
			}
		}
	}
	if (getNet().isServer())
	{
		sapper_clear_actor_limits(this);
	}

}

void onDie(CBlob@ this)
{

	SetupBomb(this, 120, 64.0f, 8.0f, 24.0f, 0.4f, true);

}

void onCommand(CBlob@ this, u8 cmd, CBitStream @params)
{

	if (cmd == this.getCommandID("get bomb"))
	{
		const u8 bombType = params.read_u8();
		if (bombType >= bombTypeNames.length)
			return;
		const string bombTypeName = bombTypeNames[bombType];
		this.Tag(bombTypeName + " done activate");
		if (hasItem(this, bombTypeName))
		{
			if (bombType == 0)
			{
				if (getNet().isServer())
				{
					CBlob @blob = server_CreateBlob("bomb", this.getTeamNum(), this.getPosition());
					if (blob !is null)
					{
						TakeItem(this, bombTypeName);
						this.server_Pickup(blob);
					}
				}
			}
			else if (bombType == 1)
			{
				if (getNet().isServer())
				{
					CBlob @blob = server_CreateBlob("waterbomb", this.getTeamNum(), this.getPosition());
					if (blob !is null)
					{
						TakeItem(this, bombTypeName);
						this.server_Pickup(blob);
						blob.set_f32("map_damage_ratio", 0.0f);
						blob.set_f32("explosive_damage", 0.0f);
						blob.set_f32("explosive_radius", 92.0f);
						blob.set_bool("map_damage_raycast", false);
						blob.set_string("custom_explosion_sound", "/GlassBreak");
						blob.set_u8("custom_hitter", Hitters::water);
					}
				}
			}
			else
			{
			}
			SetFirstAvailableBomb(this);
		}
	}
	else if (cmd == this.getCommandID("cycle"))  //from standardcontrols
	{
		// cycle arrows
		u8 type = this.get_u8("bomb type");
		int count = 0;
		while (count < bombTypeNames.length)
		{
			type++;
			count++;
			if (type >= bombTypeNames.length)
				type = 0;
			if (this.getBlobCount(bombTypeNames[type]) > 0)
			{
				this.set_u8("bomb type", type);
				if (this.isMyPlayer())
				{
					Sound::Play("/CycleInventory.ogg");
				}
				break;
			}
		}
	}
	else if (cmd == this.getCommandID("activate/throw"))
	{
		SetFirstAvailableBomb(this);
	}
	else
	{
		for (uint i = 0; i < bombTypeNames.length; i++)
		{
			if (cmd == this.getCommandID("pick " + bombTypeNames[i]))
			{
				this.set_u8("bomb type", i);
				break;
			}
		}
	}

}

f32 onHit(CBlob@ this, Vec2f worldPoint, Vec2f velocity, f32 damage, CBlob@ hitterBlob, u8 customData)
{

	CPlayer@ player=this.getPlayer();
	if(this.hasTag("invincible") || (player !is null && player.freeze)) {
		return 0;
	}
	if(Hitters::bomb == customData)return 0;
	return damage; //no block, damage goes through

}

bool isSliding(SapperInfo@ sapper)
{

	return (sapper.slideTime > 0 && sapper.slideTime < 45);

}

void onCollision(CBlob@ this, CBlob@ blob, bool solid, Vec2f normal, Vec2f point1)
{

	//return if we didn't collide or if it's teamie
	if (blob is null || !solid || this.getTeamNum() == blob.getTeamNum())
	{
		return;
	}
	const bool onground = this.isOnGround();
	if (this.getShape().vellen > SHIELD_KNOCK_VELOCITY || onground)
	{
		SapperInfo@ sapper;
		if (!this.get("sapperInfo", @sapper))
		{
			return;
		}
		//printf("sapper.stat " + sapper.state );
	}

}

void pushForward(CBlob@ this, f32 normalForce, f32 pushingForce, f32 verticalForce)
{

	f32 facing_sign = this.isFacingLeft() ? -1.0f : 1.0f ;
	bool pushing_in_facing_direction =
	    (facing_sign < 0.0f && this.isKeyPressed(key_left)) ||
	    (facing_sign > 0.0f && this.isKeyPressed(key_right));
	f32 force = normalForce;
	if (pushing_in_facing_direction)
	{
		force = pushingForce;
	}
	this.AddForce(Vec2f(force * facing_sign , verticalForce));

}

bool hasItem(CBlob@ this, const string &in name)
{

	CBitStream reqs, missing;
	AddRequirement(reqs, "blob", name, "Bombs", 1);
	CInventory@ inv = this.getInventory();
	if (inv !is null)
	{
		return hasRequirements(inv, reqs, missing);
	}
	else
	{
		warn("our inventory was null! SapperLogic.as");
	}
	return false;

}

void TakeItem(CBlob@ this, const string &in name)
{

	CBlob@ carried = this.getCarriedBlob();
	if (carried !is null)
	{
		if (carried.getName() == name)
		{
			carried.server_Die();
			return;
		}
	}
	CBitStream reqs, missing;
	AddRequirement(reqs, "blob", name, "Bombs", 1);
	CInventory@ inv = this.getInventory();
	if (inv !is null)
	{
		if (hasRequirements(inv, reqs, missing))
		{
			server_TakeRequirements(inv, reqs);
		}
		else
		{
			warn("took a bomb even though we dont have one! SapperLogic.as");
		}
	}
	else
	{
		warn("our inventory was null! SapperLogic.as");
	}

}

void onHitBlob(CBlob@ this, Vec2f worldPoint, Vec2f velocity, f32 damage, CBlob@ hitBlob, u8 customData)
{

	SapperInfo@ sapper;
	if (!this.get("sapperInfo", @sapper))
	{
		return;
	}

}

void onCreateInventoryMenu(CBlob@ this, CBlob@ forBlob, CGridMenu @gridmenu)
{

	if (bombTypeNames.length == 0)
	{
		return;
	}
	this.ClearGridMenusExceptInventory();
	Vec2f pos(gridmenu.getUpperLeftPosition().x + 0.5f * (gridmenu.getLowerRightPosition().x - gridmenu.getUpperLeftPosition().x),
	          gridmenu.getUpperLeftPosition().y - 32 * 1 - 2 * 24);
	CGridMenu@ menu = CreateGridMenu(pos, this, Vec2f(bombTypeNames.length, 2), "Current bomb");
	u8 weaponSel = this.get_u8("bomb type");
	if (menu !is null)
	{
		menu.deleteAfterClick = false;
		for (uint i = 0; i < bombTypeNames.length; i++)
		{
			string matname = bombTypeNames[i];
			CGridButton @button = menu.AddButton(bombIcons[i], bombNames[i], this.getCommandID("pick " + matname));
			if (button !is null)
			{
				bool enabled = this.getBlobCount(bombTypeNames[i]) > 0;
				button.SetEnabled(enabled);
				button.selectOneOnClick = true;
				if (weaponSel == i)
				{
					button.SetSelected(1);
				}
			}
		}
	}

}

void onAttach(CBlob@ this, CBlob@ attached, AttachmentPoint @attachedPoint)
{

	for (uint i = 0; i < bombTypeNames.length; i++)
	{
		if (attached.getName() == bombTypeNames[i])
		{
			this.set_u8("bomb type", i);
			break;
		}
	}

}

void onAddToInventory(CBlob@ this, CBlob@ blob)
{

	const string itemname = blob.getName();
	if (this.isMyPlayer() && this.getInventory().getItemsCount() > 1)
	{
		for (uint j = 1; j < bombTypeNames.length; j++)
		{
			if (itemname == bombTypeNames[j])
			{
				SetHelp(this, "help inventory", "sapper", "$Help_Bomb1$$Swap$$Help_Bomb2$         $KEY_TAP$$KEY_F$", "", 2);
				break;
			}
		}
	}
	if (this.getInventory().getItemsCount() == 0 || itemname == "mat_bombs")
	{
		for (uint j = 0; j < bombTypeNames.length; j++)
		{
			if (itemname == bombTypeNames[j])
			{
				this.set_u8("bomb type", j);
				return;
			}
		}
	}

}

void SetFirstAvailableBomb(CBlob@ this)
{

	u8 type = 255;
	if (this.exists("bomb type"))
		type = this.get_u8("bomb type");
	CInventory@ inv = this.getInventory();
	bool typeReal = (uint(type) < bombTypeNames.length);
	if (typeReal && inv.getItem(bombTypeNames[type]) !is null)
		return;
	for (int i = 0; i < inv.getItemsCount(); i++)
	{
		const string itemname = inv.getItem(i).getName();
		for (uint j = 0; j < bombTypeNames.length; j++)
		{
			if (itemname == bombTypeNames[j])
			{
				type = j;
				break;
			}
		}
		if (type != 255)
			break;
	}
	this.set_u8("bomb type", type);

}

bool canHit(CBlob@ this, CBlob@ b)
{

	if (b.hasTag("invincible"))
		return false;
	// Don't hit temp blobs and items carried by teammates.
	if (b.isAttached())
	{
		CBlob@ carrier = b.getCarriedBlob();
		if (carrier !is null)
			if (carrier.hasTag("player")
			        && (this.getTeamNum() == carrier.getTeamNum() || b.hasTag("temp blob")))
				return false;
	}
	if (b.hasTag("dead"))
		return true;
	return b.getTeamNum() != this.getTeamNum();

}