using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LD31 { public static partial class Main { //Returns true if something is done private static bool Use(bool fake = false) { int px = player.x; int py = player.y; //Object interactions Object theObject = objects[px, py]; if (theObject != null) { //Item - Ground object interactions if (heldItem != null) { if (UseItemCombination(heldItem, theObject, px, py, fake)) return true; } if (theObject.useScript != null) { if (HandleScript(theObject.useScript, theObject, null, px, py, fake)) return true; } } //Check for other item interactions if (heldItem != null) { //Using item on tile Tile tile = tiles[px, py]; if (UseItemCombination(heldItem, tile, px, py, fake)) return true; //Non-interactive item (used alone) if (heldItem.useScript != null) { if (HandleScript(heldItem.useScript,heldItem, null, px, py, fake)) return true; } //Directional usage if (heldItem.HasProperty("directionalusage")) { if (!fake) { AskForDirection(); } else { //Check all directions for (int iy = -1; iy < 2; iy++) { for (int ix = -1; ix < 2; ix++) { if (!(ix == 0 && iy == 0)) { if (UseDirection(px + ix, py + iy, fake)) return true; } } } } } } return false; } //Returns true if something is done private static bool UseItemCombination(TileObjectOrCreature item1, TileObjectOrCreature item2, int targetX, int targetY, bool fake = false) { TileObjectOrCreature i1 = item1; TileObjectOrCreature i2 = item2; for (int orders = 0; orders < 2; orders++) { //Reverse order on second attempt if (orders == 1) { i1 = item2; i2 = item1; } if (i1.combinationScripts.ContainsKey(i2.name)) { if (HandleScript(i1.combinationScripts[i2.name], i1, i2, targetX, targetY, fake)) return true; } } return false; } //Returns true if something is done private static bool UseDirection(int targetX, int targetY, bool fake = false) { if (targetX < 0 || targetX >= WORLD_SIZE_X || targetY < 0 || targetY >= WORLD_SIZE_Y) { return false; //Can't use on edge } //Try creature for (int i = 0; i < creatures.Count; i++) { Creature creature = creatures[i]; if (creature.x == targetX && creature.y == targetY) { if (UseItemCombination(heldItem, creature, targetX, targetY, fake)) { return true; } } } //Try object Object theObject = objects[targetX, targetY]; if (theObject != null) { if (UseItemCombination(heldItem, theObject, targetX, targetY, fake)) { return true; } } //Try tile Tile theTile = tiles[targetX, targetY]; if (UseItemCombination(heldItem, theTile, targetX, targetY, fake)) return true; return false; } private static bool CallNamedScript(string scriptName, TileObjectOrCreature source, TileObjectOrCreature target, int x, int y, bool fake = false) { if (source.namedScripts.ContainsKey(scriptName)) return HandleScript(source.namedScripts[scriptName], source, target, x, y, fake); return false; } //Returns true if something is done private static bool HandleScript(Script script, TileObjectOrCreature source, TileObjectOrCreature target, int x, int y, bool fake = false) { for (int i = 0; i < script.commandLines.Count; i++) { string line = script.commandLines[i]; //Uses helper functions from Main_LoadScripts.cs string firstWord = FW(line); //---------------ACTIONS------------ if (!fake) { switch (firstWord) { //Create inventory item case "createheldobject": { string[] possibleItems = RBQM(line, script.commandLines, i); if (possibleItems.Length > 1) i += possibleItems.Length + 1; CreateHeldItem(possibleItems[random.Next(possibleItems.Length)]); } break; //Create (replace) a tile at target position case "createtile": { CreateTile(x, y, RBQ(line)); } break; //Prints debug text to screen case "debug": { VBXSE.SpriteEngine.Log(RBQ(line)); } break; //Destroy whatever item is held by the player case "destroyheld": { if (heldItem != null) { DestroyHeldItem(); } } break; //Destroys the object at player's location case "destroyobjectonground": { if (objects[x, y] != null) { DestroyObject(x, y); } } break; //Destroys the target object case "destroytarget": { if (target == heldItem) { DestroyHeldItem(); } else { DestroyObject(x, y); } } break; //Destroys the source object case "destroythis": { if (source == heldItem) { DestroyHeldItem(); } else { DestroyObject(x, y); } } break; //Create object at player position case "groundspawn": { string[] possibleItems = RBQM(line, script.commandLines, i); if (possibleItems.Length > 1) i += possibleItems.Length + 1; SpawnObject(possibleItems[random.Next(possibleItems.Length)], player.x, player.y); } break; //Makes a creature delete itself case "killself": { Creature creature = (Creature)source; DeleteCreature(creature); } break; //Moves a tile away from the player case "moveawayfromplayer": { Creature creature = (Creature)source; int diffX = creature.x - player.x; int diffY = creature.y - player.y; if (diffX != 0) diffX /= Math.Abs(diffX); //Turn it into +1/-1 if (diffY != 0) diffY /= Math.Abs(diffY); //Turn it into +1/-1 //In case of failure... if (!MoveCreatureRelative(creature, diffX, diffY)) { bool moved = false; //Try only horizontal movement? if (diffX != 0) { moved = MoveCreatureRelative(creature, diffX, 0); } //Failed again? if (!moved) { //Try moving only vertically! if (diffY != 0) { MoveCreatureRelative(creature, 0, diffY); } } } } break; //Makes a creature move to target position, if possible case "movetarget": { Creature creature = (Creature)source; MoveCreature(creature, x, y); } break; //Restores your hunger bar by the specified amount case "reducehunger": { RestoreHungerBar(Convert.ToInt32(RBQ(line))); } break; //Plays the specified sound effect case "sound": { PlaySound(RBQ(line)); } break; //Create object at target position case "spawn": { string[] possibleItems = RBQM(line, script.commandLines, i); if (possibleItems.Length > 1) i += possibleItems.Length + 1; SpawnObject(possibleItems[random.Next(possibleItems.Length)], x, y); } break; //Spawn creature at target position case "spawncreature": { SpawnCreature(RBQ(line), x, y); } break; //Changes target position to a random adjacent tile (hor, vert or diag) case "targetnearby": { bool success = false; while (!success) { int relativeX = random.Next(3) - 1; //-1 to +1 int relativeY = random.Next(3) - 1; //-1 to +1 if (!(relativeX == 0 && relativeY == 0)) { int tx = x + relativeX; int ty = y + relativeY; if (tx >= 0 && tx < WORLD_SIZE_X) { if (ty >= 0 && ty < WORLD_SIZE_Y) { success = true; x = tx; y = ty; } } } } } break; //---------------VARIABLE MANIPULATION------------ case "decvar": { string[] commasplit = CS(line); int toChange = -1; if (commasplit.Length > 1) toChange = -(Convert.ToInt32(RBQ(commasplit[1]))); source.ChangeVar(RBQ(commasplit[0]), toChange); } break; case "incvar": { string[] commasplit = CS(line); int toChange = 1; if (commasplit.Length > 1) toChange = Convert.ToInt32(RBQ(commasplit[1])); source.ChangeVar(RBQ(commasplit[0]), toChange); } break; case "setvar": { string[] commasplit = CS(line); int toSet = 0; if (commasplit.Length > 1) toSet = Convert.ToInt32(RBQ(commasplit[1])); source.SetVar(RBQ(commasplit[0]), toSet); } break; } } //----------CONDITIONS AND JUMPS------------- switch (firstWord) { //Exec script/fail if named var is precisely int case "BEQ": case "branchifequals": { string[] commasplit = CS(line); if (source.ReadVar(RBQ(commasplit[0])) == Convert.ToInt32(RBQ(commasplit[1]))) { return CallNamedScript(RBQ(commasplit[2]), source, target, x, y, fake); } } break; //Exec script/fail if named var is less than int case "BLT": case "branchifless": { string[] commasplit = CS(line); if (source.ReadVar(RBQ(commasplit[0])) < Convert.ToInt32(RBQ(commasplit[1]))) { return CallNamedScript(RBQ(commasplit[2]), source, target, x, y, fake); } } break; //Exec script/fail if named var is more than int case "BMT": case "branchifmore": { string[] commasplit = CS(line); if (source.ReadVar(RBQ(commasplit[0])) > Convert.ToInt32(RBQ(commasplit[1]))) { return CallNamedScript(RBQ(commasplit[2]), source, target, x, y, fake); } } break; //Exec script/fail if named var is NOT int case "BNE": case "branchifnotequal": { string[] commasplit = CS(line); if (source.ReadVar(RBQ(commasplit[0])) != Convert.ToInt32(RBQ(commasplit[1]))) { return CallNamedScript(RBQ(commasplit[2]), source, target, x, y, fake); } } break; //Exec script/fail if not at least int tiles away from player case "distancefromplayer": { string[] commasplit = CS(line); int distanceFromPlayer = Math.Abs(player.x - x) + Math.Abs(player.y - y); if (distanceFromPlayer < Convert.ToInt32(RBQ(commasplit[0]))) { if (commasplit.Length > 1) { return CallNamedScript(RBQ(commasplit[1]), source, target, x, y, fake); } return false; } } break; //Exec script/fail if there's something on the ground under player case "groundisfree": if (objects[player.x, player.y] != null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script/fail if the player isn't holding any item case "holdingitem": if (heldItem == null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //The item must be held to use, otherwise it execs script/fails case "itemisheld": if (heldItem != source) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script/fail if the player is holding the item case "itemnotheld": if (heldItem == source) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script or fail case "jump": return CallNamedScript(RBQ(line), source, target, x, y, fake); //Exec script/fail if player is holding any item case "nohelditem": if (heldItem != null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script/fail if creature is near world edge case "notnearedge": { Creature creature = (Creature)source; if (creature.x == 0 || creature.x == WORLD_SIZE_X - 1 || creature.y == 0 || creature.y == WORLD_SIZE_Y - 1) { return CallNamedScript(RBQ(line), source, target, x, y, fake); } } break; //Exec script/fail if target location is solid case "notsolid": { if (CheckAllSolid(x, y, source)) return CallNamedScript(RBQ(line), source, target, x, y, fake); } break; //- Exec script/fail if it's summer case "notsummer": { if (currentSeason == Season.Summer) return CallNamedScript(RBQ(line), source, target, x, y, fake); } break; //- Exec script/fail if it's winter case "notwinter": { if (currentSeason == Season.Winter) return CallNamedScript(RBQ(line), source, target, x, y, fake); } break; //Exec script/fail if there's nothing on the ground under the player case "objectonground": if (objects[player.x, player.y] == null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //If rand() > float, exec script/fail case "random": { if (fake) return true; string[] commasplit = CS(line); if (random.NextDouble() > ReadFloat(RBQ(commasplit[0]))) { if (commasplit.Length > 1) { return CallNamedScript(RBQ(commasplit[1]), source, target, x, y, fake); } return false; } } break; //Exec script/fail if there's something on the ground at target position case "targetgroundisfree": if (objects[x, y] != null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script/fail if there's nothing on the ground at target position case "targetobjectonground": if (objects[x, y] == null) return CallNamedScript(RBQ(line), source, target, x, y, fake); break; //Exec script/fail if tile at target location has named property case "tilenotproperty": { string[] commasplit = CS(line); if (tiles[x, y].HasProperty(RBQ(commasplit[0]))) { if (commasplit.Length > 1) return CallNamedScript(RBQ(commasplit[1]), source, target, x, y, fake); else return false; } } break; } } return true; } private static float ReadFloat(string source) { try { float result = 0; if (source.Contains(".")) { string[] splitstring = source.Split(new string[] { "." }, StringSplitOptions.None); result = float.Parse(splitstring[0]) + (float.Parse(splitstring[1]) / ((float)Math.Pow(10, splitstring[1].Length))); } else if (source.Contains(",")) { string[] splitstring = source.Split(new string[] { "," }, StringSplitOptions.None); result = float.Parse(splitstring[0]) + (float.Parse(splitstring[1]) / ((float)Math.Pow(10, splitstring[1].Length))); } else result = float.Parse(source); return result; } catch (Exception) { return 0; } } } }