private void OnInventoryChanged(Ink.Runtime.InkList newList) { SetupInventoryItems(newList.all); list = newList; if (logInventoryChanges) { Debug.Log($"Inventory update: {newList}"); } InventoryChanged?.Invoke(items.Where(i => newList.Contains(i.value)).ToArray()); }
/// <summary> /// Returns true if the current list contains all the items that are in the list that /// is passed in. Equivalent to calling (list1 ? list2) in ink. /// </summary> /// <param name="otherList">Other list.</param> public bool Contains(InkList otherList) { foreach (var kv in otherList) { if (!this.ContainsKey(kv.Key)) { return(false); } } return(true); }
/// <summary> /// Fast test for the existence of any intersection between the current list and another /// </summary> public bool HasIntersection(InkList otherList) { foreach (var kv in this) { if (otherList.ContainsKey(kv.Key)) { return(true); } } return(false); }
/// <summary> /// Returns true if the item values in the current list overlap or are all greater than /// the item values in the passed in list. None of the item values in the current list must /// fall below the item values in the passed in list. Equivalent to (list1 >= list2) in ink, /// or LIST_MIN(list1) >= LIST_MIN(list2) && LIST_MAX(list1) >= LIST_MAX(list2). /// </summary> public bool GreaterThanOrEquals(InkList otherList) { if (Count == 0) { return(false); } if (otherList.Count == 0) { return(true); } return(minItem.Value >= otherList.minItem.Value && maxItem.Value >= otherList.maxItem.Value); }
/// <summary> /// Returns true if all the item values in the current list are less than all the /// item values in the passed in list. Equivalent to calling (list1 < list2) in ink. /// </summary> public bool LessThan(InkList otherList) { if (otherList.Count == 0) { return(false); } if (Count == 0) { return(true); } return(maxItem.Value < otherList.minItem.Value); }
/// <summary> /// Returns a new list that is the intersection of the current list with another /// list that's passed in - i.e. a list of the items that are shared between the /// two other lists. Equivalent to calling (list1 ^ list2) in ink. /// </summary> public InkList Intersect(InkList otherList) { var intersection = new InkList(); foreach (var kv in this) { if (otherList.ContainsKey(kv.Key)) { intersection.Add(kv.Key, kv.Value); } } return(intersection); }
/// <summary> /// Returns true if all the item values in the current list are greater than all the /// item values in the passed in list. Equivalent to calling (list1 > list2) in ink. /// </summary> public bool GreaterThan(InkList otherList) { if (Count == 0) { return(false); } if (otherList.Count == 0) { return(true); } // All greater return(minItem.Value > otherList.maxItem.Value); }
/// <summary> /// Returns a sublist with the elements given the minimum and maxmimum bounds. /// The bounds can either be ints which are indices into the entire (sorted) list, /// or they can be InkLists themselves. These are intended to be single-item lists so /// you can specify the upper and lower bounds. If you pass in multi-item lists, it'll /// use the minimum and maximum items in those lists respectively. /// WARNING: Calling this method requires a full sort of all the elements in the list. /// </summary> public InkList ListWithSubRange(object minBound, object maxBound) { if (this.Count == 0) { return(new InkList()); } var ordered = orderedItems; int minValue = 0; int maxValue = int.MaxValue; if (minBound is int) { minValue = (int)minBound; } else { if (minBound is InkList && ((InkList)minBound).Count > 0) { minValue = ((InkList)minBound).minItem.Value; } } if (maxBound is int) { maxValue = (int)maxBound; } else { if (minBound is InkList && ((InkList)minBound).Count > 0) { maxValue = ((InkList)maxBound).maxItem.Value; } } var subList = new InkList(); subList.SetInitialOriginNames(originNames); foreach (var item in ordered) { if (item.Value >= minValue && item.Value <= maxValue) { subList.Add(item.Key, item.Value); } } return(subList); }
public ListValue ListRange(int min, int max) { var rawList = new InkList(); foreach (var nameAndValue in _itemNameToValues) { if (nameAndValue.Value >= min && nameAndValue.Value <= max) { var item = new InkListItem(name, nameAndValue.Key); rawList [item] = nameAndValue.Value; } } return(new ListValue(rawList)); }
/// <summary> /// Converts an integer value into a list containing an item from a given list /// </summary> public static InkList FromValue(InkList list, int itemVal) { if (list.origins == null || list.origins.Count == 0) { throw new System.Exception("LIST_GET_ITEM: No origin exists in list passed into InkList.FromValue"); } var origin = list.origins[0]; InkListItem foundItem; if (origin.TryGetItemWithValue(itemVal, out foundItem)) { return(new Ink.Runtime.InkList { { foundItem, itemVal } }); } throw new System.Exception("LIST_GET_ITEM: Item with value " + itemVal + " couldn't be found in list " + origin.name); }
public static Value Create(object val) { // Implicitly lose precision from any doubles we get passed in if (val is double) { double doub = (double)val; val = (float)doub; } // Implicitly convert bools into ints if (val is bool) { bool b = (bool)val; val = (int)(b ? 1 : 0); } if (val is int || val is long) { return(new IntValue(Convert.ToInt32(val))); } else if (val is float || val is double) { return(new FloatValue(Convert.ToSingle(val))); } else if (val is string) { return(new StringValue((string)val)); } else if (val is Path) { return(new DivertTargetValue((Path)val)); } else if (val is InkList) { return(new ListValue((InkList)val)); } else if (val is IDictionary <string, object> ) { var list = new InkList(val as IDictionary <string, object>); return(new ListValue(list)); } throw new ArgumentException($"Can't create Value from object: {val}"); }
public Godot.Object create_ink_list_with_origin(string single_origin_list_name) { if (story == null) { PushNullStoryError(); return(null); } try { var inkList = new Ink.Runtime.InkList(single_origin_list_name, story); return(inkBridger.MakeGDInkList(inkList)); } catch (Exception e) { HandleException(e); return(null); } }
Value CallListIncrementOperation(List <Object> listIntParams) { var listVal = (ListValue)listIntParams[0]; var intVal = (IntValue)listIntParams[1]; var resultRawList = new InkList(); foreach (var listItemWithValue in listVal.value) { var listItem = listItemWithValue.Key; var listItemValue = listItemWithValue.Value; // Find + or - operation var intOp = (BinaryOp <int>)_operationFuncs[ValueType.Int]; // Return value unknown until it's evaluated int targetInt = (int)intOp(listItemValue, intVal.value); // Find this item's origin (linear search should be ok, should be short haha) ListDefinition itemOrigin = null; foreach (var origin in listVal.value.origins) { if (origin.name == listItem.originName) { itemOrigin = origin; break; } } if (itemOrigin != null) { InkListItem incrementedItem; if (itemOrigin.TryGetItemWithValue(targetInt, out incrementedItem)) { resultRawList.Add(incrementedItem, targetInt); } } } return(new ListValue(resultRawList)); }
public Godot.Object MakeGDInkList(Ink.Runtime.InkList list) { var inkListBase = new Godot.Collections.Dictionary <string, int>(); foreach (KeyValuePair <Ink.Runtime.InkListItem, int> kv in list) { inkListBase.Add(MakeGDInkListItem(kv.Key).Call("serialized") as string, kv.Value); } object[] inkListParams = new object[] { inkListBase, list.originNames.ToArray(), MakeGDInkListOrigins(list.origins) }; var inkList = (Godot.Object)InkList.New(); inkList.Call("_init_from_csharp", inkListParams); return(inkList); }
public Ink.Runtime.InkList MakeSharpInkList(Godot.Object list, Ink.Runtime.Story story) { if (!IsInkObjectOfType(list, "InkList")) { throw new ArgumentException("Expected a 'Godot.Object' of class 'InkList'"); } var underlyingDictionary = (Godot.Collections.Dictionary <Godot.Object, int>)list.Get("_dictionary"); var originNames = (Godot.Collections.Array <string>)list.Get("origin_names"); var inkList = new Ink.Runtime.InkList(); inkList.SetInitialOriginNames(originNames.ToList()); foreach (string originName in originNames) { if (story.listDefinitions.TryListGetDefinition(originName, out Ink.Runtime.ListDefinition definition)) { if (!inkList.origins.Contains(definition)) { inkList.origins.Add(definition); } } else { throw new Exception( $"InkList origin could not be found in story when reconstructing list: {originName}" ); } } foreach (KeyValuePair <Godot.Object, int> kv in underlyingDictionary) { inkList[MakeSharpInkListItem(kv.Key)] = kv.Value; } return(inkList); }
/// <summary> /// Create a new ink list that contains the same contents as another list. /// </summary> public InkList(InkList otherList) : base(otherList) { _originNames = otherList.originNames; }
// ---------------------- // JSON ENCODING SCHEME // ---------------------- // // Glue: "<>", "G<", "G>" // // ControlCommand: "ev", "out", "/ev", "du" "pop", "->->", "~ret", "str", "/str", "nop", // "choiceCnt", "turns", "visit", "seq", "thread", "done", "end" // // NativeFunction: "+", "-", "/", "*", "%" "~", "==", ">", "<", ">=", "<=", "!=", "!"... etc // // Void: "void" // // Value: "^string value", "^^string value beginning with ^" // 5, 5.2 // {"^->": "path.target"} // {"^var": "varname", "ci": 0} // // Container: [...] // [..., // { // "subContainerName": ..., // "#f": 5, // flags // "#n": "containerOwnName" // only if not redundant // } // ] // // Divert: {"->": "path.target", "c": true } // {"->": "path.target", "var": true} // {"f()": "path.func"} // {"->t->": "path.tunnel"} // {"x()": "externalFuncName", "exArgs": 5} // // Var Assign: {"VAR=": "varName", "re": true} // reassignment // {"temp=": "varName"} // // Var ref: {"VAR?": "varName"} // {"CNT?": "stitch name"} // // ChoicePoint: {"*": pathString, // "flg": 18 } // // Choice: Nothing too clever, it's only used in the save state, // there's not likely to be many of them. // // Tag: {"#": "the tag text"} public static Runtime.Object JTokenToRuntimeObject(object token) { if (token is int || token is float) { return(Value.Create(token)); } if (token is string) { string str = (string)token; // String value char firstChar = str[0]; if (firstChar == '^') { return(new StringValue(str.Substring(1))); } else if (firstChar == '\n' && str.Length == 1) { return(new StringValue("\n")); } // Glue if (str == "<>") { return(new Runtime.Glue()); } // Control commands (would looking up in a hash set be faster?) for (int i = 0; i < _controlCommandNames.Length; ++i) { string cmdName = _controlCommandNames [i]; if (str == cmdName) { return(new Runtime.ControlCommand((ControlCommand.CommandType)i)); } } // Native functions // "^" conflicts with the way to identify strings, so now // we know it's not a string, we can convert back to the proper // symbol for the operator. if (str == "L^") { str = "^"; } if (NativeFunctionCall.CallExistsWithName(str)) { return(NativeFunctionCall.CallWithName(str)); } // Pop if (str == "->->") { return(Runtime.ControlCommand.PopTunnel()); } else if (str == "~ret") { return(Runtime.ControlCommand.PopFunction()); } // Void if (str == "void") { return(new Runtime.Void()); } } if (token is Dictionary <string, object> ) { var obj = (Dictionary <string, object>)token; object propValue; // Divert target value to path if (obj.TryGetValue("^->", out propValue)) { return(new DivertTargetValue(new Path((string)propValue))); } // VariablePointerValue if (obj.TryGetValue("^var", out propValue)) { var varPtr = new VariablePointerValue((string)propValue); if (obj.TryGetValue("ci", out propValue)) { varPtr.contextIndex = (int)propValue; } return(varPtr); } // Divert bool isDivert = false; bool pushesToStack = false; PushPopType divPushType = PushPopType.Function; bool external = false; if (obj.TryGetValue("->", out propValue)) { isDivert = true; } else if (obj.TryGetValue("f()", out propValue)) { isDivert = true; pushesToStack = true; divPushType = PushPopType.Function; } else if (obj.TryGetValue("->t->", out propValue)) { isDivert = true; pushesToStack = true; divPushType = PushPopType.Tunnel; } else if (obj.TryGetValue("x()", out propValue)) { isDivert = true; external = true; pushesToStack = false; divPushType = PushPopType.Function; } if (isDivert) { var divert = new Divert(); divert.pushesToStack = pushesToStack; divert.stackPushType = divPushType; divert.isExternal = external; string target = propValue.ToString(); if (obj.TryGetValue("var", out propValue)) { divert.variableDivertName = target; } else { divert.targetPathString = target; } divert.isConditional = obj.TryGetValue("c", out propValue); if (external) { if (obj.TryGetValue("exArgs", out propValue)) { divert.externalArgs = (int)propValue; } } return(divert); } // Choice if (obj.TryGetValue("*", out propValue)) { var choice = new ChoicePoint(); choice.pathStringOnChoice = propValue.ToString(); if (obj.TryGetValue("flg", out propValue)) { choice.flags = (int)propValue; } return(choice); } // Variable reference if (obj.TryGetValue("VAR?", out propValue)) { return(new VariableReference(propValue.ToString())); } else if (obj.TryGetValue("CNT?", out propValue)) { var readCountVarRef = new VariableReference(); readCountVarRef.pathStringForCount = propValue.ToString(); return(readCountVarRef); } // Variable assignment bool isVarAss = false; bool isGlobalVar = false; if (obj.TryGetValue("VAR=", out propValue)) { isVarAss = true; isGlobalVar = true; } else if (obj.TryGetValue("temp=", out propValue)) { isVarAss = true; isGlobalVar = false; } if (isVarAss) { var varName = propValue.ToString(); var isNewDecl = !obj.TryGetValue("re", out propValue); var varAss = new VariableAssignment(varName, isNewDecl); varAss.isGlobal = isGlobalVar; return(varAss); } // Tag if (obj.TryGetValue("#", out propValue)) { return(new Runtime.Tag((string)propValue)); } // List value if (obj.TryGetValue("list", out propValue)) { var listContent = (Dictionary <string, object>)propValue; var rawList = new InkList(); if (obj.TryGetValue("origins", out propValue)) { var namesAsObjs = (List <object>)propValue; rawList.SetInitialOriginNames(namesAsObjs.Cast <string>().ToList()); } foreach (var nameToVal in listContent) { var item = new InkListItem(nameToVal.Key); var val = (int)nameToVal.Value; rawList.Add(item, val); } return(new ListValue(rawList)); } // Used when serialising save state only if (obj ["originalChoicePath"] != null) { return(JObjectToChoice(obj)); } } // Array is always a Runtime.Container if (token is List <object> ) { return(JArrayToContainer((List <object>)token)); } if (token == null) { return(null); } throw new System.Exception("Failed to convert token to runtime object: " + token); }