diff --git a/1.5/Assemblies/0Harmony.dll b/1.5/Assemblies/0Harmony.dll new file mode 100644 index 0000000..86fc5eb Binary files /dev/null and b/1.5/Assemblies/0Harmony.dll differ diff --git a/1.5/Assemblies/0Harmony.xml b/1.5/Assemblies/0Harmony.xml new file mode 100644 index 0000000..f1b9b4c --- /dev/null +++ b/1.5/Assemblies/0Harmony.xml @@ -0,0 +1,3693 @@ + + + + 0Harmony + + + + A factory to create delegate types + + + Default constructor + + + Creates a delegate type for a method + The method + The new delegate type + + + + A getter delegate type + Type that getter gets field/property value from + Type of the value that getter gets + The instance get getter uses + An delegate + + + + A setter delegate type + Type that setter sets field/property value for + Type of the value that setter sets + The instance the setter uses + The value the setter uses + An delegate + + + + A constructor delegate type + Type that constructor creates + An delegate + + + + A helper class for fast access to getters and setters + + + Creates an instantiation delegate + Type that constructor creates + The new instantiation delegate + + + + Creates an getter delegate for a property + Type that getter reads property from + Type of the property that gets accessed + The property + The new getter delegate + + + + Creates an getter delegate for a field + Type that getter reads field from + Type of the field that gets accessed + The field + The new getter delegate + + + + Creates an getter delegate for a field (with a list of possible field names) + Type that getter reads field/property from + Type of the field/property that gets accessed + A list of possible field names + The new getter delegate + + + + Creates an setter delegate + Type that setter assigns property value to + Type of the property that gets assigned + The property + The new setter delegate + + + + Creates an setter delegate for a field + Type that setter assigns field value to + Type of the field that gets assigned + The field + The new getter delegate + + + + A delegate to invoke a method + The instance + The method parameters + The method result + + + A helper class to invoke method with delegates + + + Creates a fast invocation handler from a method + The method to invoke + Controls if boxed value object is accessed/updated directly + The + + + The directBoxValueAccess option controls how value types passed by reference (e.g. ref int, out my_struct) are handled in the arguments array + passed to the fast invocation handler. + Since the arguments array is an object array, any value types contained within it are actually references to a boxed value object. + Like any other object, there can be other references to such boxed value objects, other than the reference within the arguments array. + For example, + + var val = 5; + var box = (object)val; + var arr = new object[] { box }; + handler(arr); // for a method with parameter signature: ref/out/in int + + + + + If directBoxValueAccess is true, the boxed value object is accessed (and potentially updated) directly when the handler is called, + such that all references to the boxed object reflect the potentially updated value. + In the above example, if the method associated with the handler updates the passed (boxed) value to 10, both box and arr[0] + now reflect the value 10. Note that the original val is not updated, since boxing always copies the value into the new boxed value object. + + + If directBoxValueAccess is false (default), the boxed value object in the arguments array is replaced with a "reboxed" value object, + such that potential updates to the value are reflected only in the arguments array. + In the above example, if the method associated with the handler updates the passed (boxed) value to 10, only arr[0] now reflects the value 10. + + + + + A low level memory helper + + + + Mark method for no inlining (currently only works on Mono) + The method/constructor to change + + + + Detours a method + The original method/constructor + The replacement method/constructor + An error string + + + + Writes a jump to memory + The memory address + Jump destination + An error string + + + + Gets the start of a method in memory + The method/constructor + [out] Details of the exception + The method start address + + + + special parameter names that can be used in prefix and postfix methods + + + Patch function helpers + + + Sorts patch methods by their priority rules + The original method + Patches to sort + Use debug mode + The sorted patch methods + + + + Creates new replacement method with the latest patches and detours the original method + The original method + Information describing the patches + The newly created replacement method + + + + Creates a patch sorter + Array of patches that will be sorted + Use debugging + + + Sorts internal PatchSortingWrapper collection and caches the results. + After first run the result is provided from the cache. + The original method + The sorted patch methods + + + Checks if the sorter was created with the same patch list and as a result can be reused to + get the sorted order of the patches. + List of patches to check against + true if equal + + + Removes one unresolved dependency from the least important patch. + + + Outputs all unblocked patches from the waiting list to results list + + + Adds patch to both results list and handled patches set + Patch to add + + + Wrapper used over the Patch object to allow faster dependency access and + dependency removal in case of cyclic dependencies + + + Create patch wrapper object used for sorting + Patch to wrap + + + Determines how patches sort + The other patch + integer to define sort order (-1, 0, 1) + + + Determines whether patches are equal + The other patch + true if equal + + + Hash function + A hash code + + + Bidirectionally registers Patches as after dependencies + List of dependencies to register + + + Bidirectionally registers Patches as before dependencies + List of dependencies to register + + + Bidirectionally removes Patch from after dependencies + Patch to remove + + + Bidirectionally removes Patch from before dependencies + Patch to remove + + + Specifies the type of method + + + + This is a normal method + + + This is a getter + + + This is a setter + + + This is a constructor + + + This is a static constructor + + + This targets the MoveNext method of the enumerator result + + + Specifies the type of argument + + + + This is a normal argument + + + This is a reference argument (ref) + + + This is an out argument (out) + + + This is a pointer argument (&) + + + Specifies the type of patch + + + + Any patch + + + A prefix patch + + + A postfix patch + + + A transpiler + + + A finalizer + + + A reverse patch + + + Specifies the type of reverse patch + + + + Use the unmodified original method (directly from IL) + + + Use the original as it is right now including previous patches but excluding future ones + + + Specifies the type of method call dispatching mechanics + + + + Call the method using dynamic dispatching if method is virtual (including overriden) + + + This is the built-in form of late binding (a.k.a. dynamic binding) and is the default dispatching mechanic in C#. + This directly corresponds with the instruction. + + + For virtual (including overriden) methods, the instance type's most-derived/overriden implementation of the method is called. + For non-virtual (including static) methods, same behavior as : the exact specified method implementation is called. + + + Note: This is not a fully dynamic dispatch, since non-virtual (including static) methods are still called non-virtually. + A fully dynamic dispatch in C# involves using + the dynamic type + (actually a fully dynamic binding, since even the name and overload resolution happens at runtime), which does not support. + + + + + Call the method using static dispatching, regardless of whether method is virtual (including overriden) or non-virtual (including static) + + + a.k.a. non-virtual dispatching, early binding, or static binding. + This directly corresponds with the instruction. + + + For both virtual (including overriden) and non-virtual (including static) methods, the exact specified method implementation is called, without virtual/override mechanics. + + + + + The base class for all Harmony annotations (not meant to be used directly) + + + + The common information for all attributes + + + Annotation to define your Harmony patch methods + + + + An empty annotation can be used together with TargetMethod(s) + + + + An annotation that specifies a class to patch + The declaring class/type + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The argument types of the method or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + The full name of the declaring class/type + The name of the method, property or constructor to patch + The + + + + Annotation to define the original method for delegate injection + + + + An annotation that specifies a class to patch + The declaring class/type + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The argument types of the method or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + The + + + + An annotation that specifies call dispatching mechanics for the delegate + The + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + Annotation to define your standin methods for reverse patching + + + + An annotation that specifies the type of reverse patching + The of the reverse patch + + + + A Harmony annotation to define that all methods in a class are to be patched + + + + A Harmony annotation + + + + A Harmony annotation to define patch priority + The priority + + + + A Harmony annotation + + + + A Harmony annotation to define that a patch comes before another patch + The array of harmony IDs of the other patches + + + + A Harmony annotation + + + A Harmony annotation to define that a patch comes after another patch + The array of harmony IDs of the other patches + + + + A Harmony annotation + + + A Harmony annotation to debug a patch (output uses to log to your Desktop) + + + + Specifies the Prepare function in a patch class + + + + Specifies the Cleanup function in a patch class + + + + Specifies the TargetMethod function in a patch class + + + + Specifies the TargetMethods function in a patch class + + + + Specifies the Prefix function in a patch class + + + + Specifies the Postfix function in a patch class + + + + Specifies the Transpiler function in a patch class + + + + Specifies the Finalizer function in a patch class + + + + A Harmony annotation + + + + The name of the original argument + + + + The index of the original argument + + + + The new name of the original argument + + + + An annotation to declare injected arguments by name + + + + An annotation to declare injected arguments by index + Zero-based index + + + + An annotation to declare injected arguments by renaming them + Name of the original argument + New name + + + + An annotation to declare injected arguments by index and renaming them + Zero-based index + New name + + + + An abstract wrapper around OpCode and their operands. Used by transpilers + + + + The opcode + + + + The operand + + + + All labels defined on this instruction + + + + All exception block boundaries defined on this instruction + + + + Creates a new CodeInstruction with a given opcode and optional operand + The opcode + The operand + + + + Create a full copy (including labels and exception blocks) of a CodeInstruction + The to copy + + + + Clones a CodeInstruction and resets its labels and exception blocks + A lightweight copy of this code instruction + + + + Clones a CodeInstruction, resets labels and exception blocks and sets its opcode + The opcode + A copy of this CodeInstruction with a new opcode + + + + Clones a CodeInstruction, resets labels and exception blocks and sets its operand + The operand + A copy of this CodeInstruction with a new operand + + + + Creates a CodeInstruction calling a method (CALL) + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A code instruction that calls the method matching the arguments + + + + Creates a CodeInstruction calling a method (CALL) + The target method in the form TypeFullName:MethodName, where the type name matches a form recognized by Type.GetType like Some.Namespace.Type. + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A code instruction that calls the method matching the arguments + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Returns an instruction to call the specified closure + The delegate type to emit + The closure that defines the method to call + A that calls the closure as a method + + + + Creates a CodeInstruction loading a field (LD[S]FLD[A]) + The class/type where the field is defined + The name of the field (case sensitive) + Use address of field + + + + Creates a CodeInstruction storing to a field (ST[S]FLD) + The class/type where the field is defined + The name of the field (case sensitive) + + + + Returns a string representation of the code instruction + A string representation of the code instruction + + + + Exception block types + + + + The beginning of an exception block + + + + The beginning of a catch block + + + + The beginning of an except filter block (currently not supported to use in a patch) + + + + The beginning of a fault block + + + + The beginning of a finally block + + + + The end of an exception block + + + + An exception block + + + + Block type + + + + Catch type + + + + Creates an exception block + The + The catch type + + + + The Harmony instance is the main entry to Harmony. After creating one with an unique identifier, it is used to patch and query the current application domain + + + + The unique identifier + + + + Set to true before instantiating Harmony to debug Harmony or use an environment variable to set HARMONY_DEBUG to '1' like this: cmd /C "set HARMONY_DEBUG=1 && game.exe" + This is for full debugging. To debug only specific patches, use the attribute + + + + Creates a new Harmony instance + A unique identifier (you choose your own) + A Harmony instance + + + + Searches the current assembly for Harmony annotations and uses them to create patches + This method can fail to use the correct assembly when being inlined. It calls StackTrace.GetFrame(1) which can point to the wrong method/assembly. If you are unsure or run into problems, use PatchAll(Assembly.GetExecutingAssembly()) instead. + + + + Creates a empty patch processor for an original method + The original method/constructor + A new instance + + + + Creates a patch class processor from an annotated class + The class/type + A new instance + + + + Creates a reverse patcher for one of your stub methods + The original method/constructor + The stand-in stub method as + A new instance + + + + Searches an assembly for Harmony annotations and uses them to create patches + The assembly + + + + Creates patches by manually specifying the methods + The original method/constructor + An optional prefix method wrapped in a object + An optional postfix method wrapped in a object + An optional transpiler method wrapped in a object + An optional finalizer method wrapped in a object + The replacement method that was created to patch the original method + + + + Patches a foreign method onto a stub method of yours and optionally applies transpilers during the process + The original method/constructor you want to duplicate + Your stub method as that will become the original. Needs to have the correct signature (either original or whatever your transpilers generates) + An optional transpiler as method that will be applied during the process + The replacement method that was created to patch the stub method + + + + Unpatches methods by patching them with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The optional Harmony ID to restrict unpatching to a specific Harmony instance + This method could be static if it wasn't for the fact that unpatching creates a new replacement method that contains your harmony ID + + + + Unpatches a method by patching it with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The original method/constructor + The + The optional Harmony ID to restrict unpatching to a specific Harmony instance + + + + Unpatches a method by patching it with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The original method/constructor + The patch method as method to remove + + + + Test for patches from a specific Harmony ID + The Harmony ID + True if patches for this ID exist + + + + Gets patch information for a given original method + The original method/constructor + The patch information as + + + + Gets the methods this instance has patched + An enumeration of original methods/constructors + + + + Gets all patched original methods in the appdomain + An enumeration of patched original methods/constructors + + + + Gets the original method from a given replacement method + A replacement method, for example from a stacktrace + The original method/constructor or null if not found + + + + Tries to get the method from a stackframe including dynamic replacement methods + The + For normal frames, frame.GetMethod() is returned. For frames containing patched methods, the replacement method is returned or null if no method can be found + + + + Gets the original method from the stackframe and uses original if method is a dynamic replacement + The + The original method from that stackframe + + + Gets Harmony version for all active Harmony instances + [out] The current Harmony version + A dictionary containing assembly versions keyed by Harmony IDs + + + + Under Mono, HarmonyException wraps IL compile errors with detailed information about the failure + + + + Default serialization constructor (not implemented) + The info + The context + + + + Get a list of IL instructions in pairs of offset+code + A list of key/value pairs which represent an offset and the code at that offset + + + + Get a list of IL instructions without offsets + A list of + + + + Get the error offset of the errornous IL instruction + The offset + + + + Get the index of the errornous IL instruction + The index into the list of instructions or -1 if not found + + + + A wrapper around a method to use it as a patch (for example a Prefix) + + + + The original method + + + + Class/type declaring this patch + + + + Patch method name + + + + Optional patch + + + + Array of argument types of the patch method + + + + of the patch + + + + Install this patch before patches with these Harmony IDs + + + + Install this patch after patches with these Harmony IDs + + + + Reverse patch type, see + + + + Create debug output for this patch + + + + Whether to use (true) or (false) mechanics + for -attributed delegate + + + + Default constructor + + + + Creates a patch from a given method + The original method + + + + Creates a patch from a given method + The original method + The patch + A list of harmony IDs that should come after this patch + A list of harmony IDs that should come before this patch + Set to true to generate debug output + + + + Creates a patch from a given method + The patch class/type + The patch method name + The optional argument types of the patch method (for overloaded methods) + + + + Gets the names of all internal patch info fields + A list of field names + + + + Merges annotations + The list of to merge + The merged + + + + Returns a string that represents the annotation + A string representation + + + + Annotation extensions + + + + Copies annotation information + The source + The destination + + + + Clones an annotation + The to clone + A copied + + + + Merges annotations + The master + The detail + A new, merged + + + + Gets all annotations on a class/type + The class/type + A list of all + + + + Gets merged annotations on a class/type + The class/type + The merged + + + + Gets all annotations on a method + The method/constructor + A list of + + + + Gets merged annotations on a method + The method/constructor + The merged + + + + + A mutable representation of an inline signature, similar to Mono.Cecil's CallSite. + Used by the calli instruction, can be used by transpilers + + + + + See + + + + See + + + + See + + + + The list of all parameter types or function pointer signatures received by the call site + + + + The return type or function pointer signature returned by the call site + + + + Returns a string representation of the inline signature + A string representation of the inline signature + + + + + A mutable representation of a parameter type with an attached type modifier, + similar to Mono.Cecil's OptionalModifierType / RequiredModifierType and C#'s modopt / modreq + + + + + Whether this is a modopt (optional modifier type) or a modreq (required modifier type) + + + + The modifier type attached to the parameter type + + + + The modified parameter type + + + + Returns a string representation of the modifier type + A string representation of the modifier type + + + + Patch serialization + + + + Control the binding of a serialized object to a type + Specifies the assembly name of the serialized object + Specifies the type name of the serialized object + The type of the object the formatter creates a new instance of + + + + Serializes a patch info + The + The serialized data + + + + Deserialize a patch info + The serialized data + A + + + + Compare function to sort patch priorities + The patch + Zero-based index + The priority + A standard sort integer (-1, 0, 1) + + + + Serializable patch information + + + + Prefixes as an array of + + + + Postfixes as an array of + + + + Transpilers as an array of + + + + Finalizers as an array of + + + + Returns if any of the patches wants debugging turned on + + + + Adds prefixes + An owner (Harmony ID) + The patch methods + + + + Adds a prefix + + + Removes prefixes + The owner of the prefixes, or * for all + + + + Adds postfixes + An owner (Harmony ID) + The patch methods + + + + Adds a postfix + + + Removes postfixes + The owner of the postfixes, or * for all + + + + Adds transpilers + An owner (Harmony ID) + The patch methods + + + + Adds a transpiler + + + Removes transpilers + The owner of the transpilers, or * for all + + + + Adds finalizers + An owner (Harmony ID) + The patch methods + + + + Adds a finalizer + + + Removes finalizers + The owner of the finalizers, or * for all + + + + Removes a patch using its method + The method of the patch to remove + + + + Gets a concatenated list of patches + The Harmony instance ID adding the new patches + The patches to add + The current patches + + + + Gets a list of patches with any from the given owner removed + The owner of the methods, or * for all + The current patches + + + + A serializable patch + + + + Zero-based index + + + + The owner (Harmony ID) + + + + The priority, see + + + + Keep this patch before the patches indicated in the list of Harmony IDs + + + + Keep this patch after the patches indicated in the list of Harmony IDs + + + + A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future + + + + The method of the static patch method + + + + Creates a patch + The method of the patch + Zero-based index + An owner (Harmony ID) + The priority, see + A list of Harmony IDs for patches that should run after this patch + A list of Harmony IDs for patches that should run before this patch + A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future + + + + Creates a patch + The method of the patch + Zero-based index + An owner (Harmony ID) + + + Get the patch method or a DynamicMethod if original patch method is a patch factory + The original method/constructor + The method of the patch + + + + Determines whether patches are equal + The other patch + true if equal + + + + Determines how patches sort + The other patch + integer to define sort order (-1, 0, 1) + + + + Hash function + A hash code + + + + A PatchClassProcessor used to turn on a class/type into patches + + + + Creates a patch class processor by pointing out a class. Similar to PatchAll() but without searching through all classes. + The Harmony instance + The class to process (need to have at least a [HarmonyPatch] attribute) + + + + Applies the patches + A list of all created replacement methods or null if patch class is not annotated + + + + A group of patches + + + + A collection of prefix + + + + A collection of postfix + + + + A collection of transpiler + + + + A collection of finalizer + + + + Gets all owners (Harmony IDs) or all known patches + The patch owners + + + + Creates a group of patches + An array of prefixes as + An array of postfixes as + An array of transpileres as + An array of finalizeres as + + + + A PatchProcessor handles patches on a method/constructor + + + + Creates an empty patch processor + The Harmony instance + The original method/constructor + + + + Adds a prefix + The prefix as a + A for chaining calls + + + + Adds a prefix + The prefix method + A for chaining calls + + + + Adds a postfix + The postfix as a + A for chaining calls + + + + Adds a postfix + The postfix method + A for chaining calls + + + + Adds a transpiler + The transpiler as a + A for chaining calls + + + + Adds a transpiler + The transpiler method + A for chaining calls + + + + Adds a finalizer + The finalizer as a + A for chaining calls + + + + Adds a finalizer + The finalizer method + A for chaining calls + + + + Gets all patched original methods in the appdomain + An enumeration of patched method/constructor + + + + Applies all registered patches + The generated replacement method + + + + Unpatches patches of a given type and/or Harmony ID + The patch type + Harmony ID or * for any + A for chaining calls + + + + Unpatches a specific patch + The method of the patch + A for chaining calls + + + + Gets patch information on an original + The original method/constructor + The patch information as + + + + Sort patch methods by their priority rules + The original method + Patches to sort + The sorted patch methods + + + + Gets Harmony version for all active Harmony instances + [out] The current Harmony version + A dictionary containing assembly version keyed by Harmony ID + + + + Creates a new empty generator to use when reading method bodies + A new + + + + Creates a new generator matching the method/constructor to use when reading method bodies + The original method/constructor to copy method information from + A new + + + + Returns the methods unmodified list of code instructions + The original method/constructor + Optionally an existing generator that will be used to create all local variables and labels contained in the result (if not specified, an internal generator is used) + A list containing all the original + + + + Returns the methods unmodified list of code instructions + The original method/constructor + A new generator that now contains all local variables and labels contained in the result + A list containing all the original + + + + Returns the methods current list of code instructions after all existing transpilers have been applied + The original method/constructor + Apply only the first count of transpilers + Optionally an existing generator that will be used to create all local variables and labels contained in the result (if not specified, an internal generator is used) + A list of + + + + Returns the methods current list of code instructions after all existing transpilers have been applied + The original method/constructor + A new generator that now contains all local variables and labels contained in the result + Apply only the first count of transpilers + A list of + + + + A low level way to read the body of a method. Used for quick searching in methods + The original method + All instructions as opcode/operand pairs + + + + A low level way to read the body of a method. Used for quick searching in methods + The original method + An existing generator that will be used to create all local variables and labels contained in the result + All instructions as opcode/operand pairs + + + + A patch priority + + + + Patch last + + + + Patch with very low priority + + + + Patch with low priority + + + + Patch with lower than normal priority + + + + Patch with normal priority + + + + Patch with higher than normal priority + + + + Patch with high priority + + + + Patch with very high priority + + + + Patch first + + + + A reverse patcher + + + + Creates a reverse patcher + The Harmony instance + The original method/constructor + Your stand-in stub method as + + + + Applies the patch + The type of patch, see + The generated replacement method + + + + A collection of commonly used transpilers + + + + A transpiler that replaces all occurrences of a given method with another one using the same signature + The enumeration of to act on + Method or constructor to search for + Method or constructor to replace with + Modified enumeration of + + + + A transpiler that alters instructions that match a predicate by calling an action + The enumeration of to act on + A predicate selecting the instructions to change + An action to apply to matching instructions + Modified enumeration of + + + + A transpiler that logs a text at the beginning of the method + The instructions to act on + The log text + Modified enumeration of + + + + A helper class for reflection related functions + + + + Shortcut for to simplify the use of reflections and make it work for any access level + + + + Shortcut for to simplify the use of reflections and make it work for any access level but only within the current type + + + + Enumerates all assemblies in the current app domain, excluding visual studio assemblies + An enumeration of + + + Gets a type by name. Prefers a full name with namespace but falls back to the first type matching the name otherwise + The name + A type or null if not found + + + + Gets all successfully loaded types from a given assembly + The assembly + An array of types + + This calls and returns , while catching any thrown . + If such an exception is thrown, returns the successfully loaded types (, + filtered for non-null values). + + + + + Enumerates all successfully loaded types in the current app domain, excluding visual studio assemblies + An enumeration of all in all assemblies, excluding visual studio assemblies + + + Applies a function going up the type hierarchy and stops at the first non-null result + Result type of func() + The class/type to start with + The evaluation function returning T + The first non-null result, or null if no match + + The type hierarchy of a class or value type (including struct) does NOT include implemented interfaces, + and the type hierarchy of an interface is only itself (regardless of whether that interface implements other interfaces). + The top-most type in the type hierarchy of all non-interface types (including value types) is . + + + + + Applies a function going into inner types and stops at the first non-null result + Generic type parameter + The class/type to start with + The evaluation function returning T + The first non-null result, or null if no match + + + + Gets the reflection information for a directly declared field + The class/type where the field is defined + The name of the field + A field or null when type/name is null or when the field cannot be found + + + + Gets the reflection information for a directly declared field + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A field or null when the field cannot be found + + + + Gets the reflection information for a field by searching the type and all its super types + The class/type where the field is defined + The name of the field (case sensitive) + A field or null when type/name is null or when the field cannot be found + + + + Gets the reflection information for a field by searching the type and all its super types + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A field or null when the field cannot be found + + + + Gets the reflection information for a field + The class/type where the field is declared + The zero-based index of the field inside the class definition + A field or null when type is null or when the field cannot be found + + + + Gets the reflection information for a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A property or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for a directly declared property + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A property or null when the property cannot be found + + + + Gets the reflection information for the getter method of a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the getter method of a directly declared property + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A method or null when the property cannot be found + + + + Gets the reflection information for the setter method of a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the Setter method of a directly declared property + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A method or null when the property cannot be found + + + + Gets the reflection information for a property by searching the type and all its super types + The class/type + The name + A property or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for a property by searching the type and all its super types + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A property or null when the property cannot be found + + + + Gets the reflection information for the getter method of a property by searching the type and all its super types + The class/type + The name + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the getter method of a property by searching the type and all its super types + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the setter method of a property by searching the type and all its super types + The class/type + The name + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the setter method of a property by searching the type and all its super types + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for a directly declared method + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when type/name is null or when the method cannot be found + + + + Gets the reflection information for a directly declared method + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when the method cannot be found + + + + Gets the reflection information for a method by searching the type and all its super types + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when type/name is null or when the method cannot be found + + + + Gets the reflection information for a method by searching the type and all its super types + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when the method cannot be found + + + + Gets the method of an enumerator method + Enumerator method that creates the enumerator + The internal method of the enumerator or null if no valid enumerator is detected + + + Gets the names of all method that are declared in a type + The declaring class/type + A list of method names + + + + Gets the names of all method that are declared in the type of the instance + An instance of the type to search in + A list of method names + + + + Gets the names of all fields that are declared in a type + The declaring class/type + A list of field names + + + + Gets the names of all fields that are declared in the type of the instance + An instance of the type to search in + A list of field names + + + + Gets the names of all properties that are declared in a type + The declaring class/type + A list of property names + + + + Gets the names of all properties that are declared in the type of the instance + An instance of the type to search in + A list of property names + + + + Gets the type of any class member of + A member + The class/type of this member + + + + Test if a class member is actually an concrete implementation + A member + True if the member is a declared + + + + Gets the real implementation of a class member + A member + The member itself if its declared. Otherwise the member that is actually implemented in some base type + + + + Gets the reflection information for a directly declared constructor + The class/type where the constructor is declared + Optional parameters to target a specific overload of the constructor + Optional parameters to only consider static constructors + A constructor info or null when type is null or when the constructor cannot be found + + + + Gets the reflection information for a constructor by searching the type and all its super types + The class/type where the constructor is declared + Optional parameters to target a specific overload of the method + Optional parameters to only consider static constructors + A constructor info or null when type is null or when the method cannot be found + + + + Gets reflection information for all declared constructors + The class/type where the constructors are declared + Optional parameters to only consider static constructors + A list of constructor infos + + + + Gets reflection information for all declared methods + The class/type where the methods are declared + A list of methods + + + + Gets reflection information for all declared properties + The class/type where the properties are declared + A list of properties + + + + Gets reflection information for all declared fields + The class/type where the fields are declared + A list of fields + + + + Gets the return type of a method or constructor + The method/constructor + The return type + + + + Given a type, returns the first inner type matching a recursive search by name + The class/type to start searching at + The name of the inner type (case sensitive) + The inner type or null if type/name is null or if a type with that name cannot be found + + + + Given a type, returns the first inner type matching a recursive search with a predicate + The class/type to start searching at + The predicate to search with + The inner type or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first method matching a predicate + The class/type to start searching at + The predicate to search with + The method or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first constructor matching a predicate + The class/type to start searching at + The predicate to search with + The constructor info or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first property matching a predicate + The class/type to start searching at + The predicate to search with + The property or null if type/predicate is null or if a type with that name cannot be found + + + + Returns an array containing the type of each object in the given array + An array of objects + An array of types or an empty array if parameters is null (if an object is null, the type for it will be object) + + + + Creates an array of input parameters for a given method and a given set of potential inputs + The method/constructor you are planing to call + The possible input parameters in any order + An object array matching the method signature + + + + A readable/assignable reference delegate to an instance field of a class or static field (NOT an instance field of a struct) + + An arbitrary type if the field is static; otherwise the class that defines the field, or a parent class (including ), + implemented interface, or derived class of this type + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The runtime instance to access the field (ignored and can be omitted for static fields) + A readable/assignable reference to the field + Null instance passed to a non-static field ref delegate + + Instance of invalid type passed to a non-static field ref delegate + (this can happen if is a parent class or interface of the field's declaring type) + + + + This delegate cannot be used for instance fields of structs, since a struct instance passed to the delegate would be passed by + value and thus would be a copy that only exists within the delegate's invocation. This is fine for a readonly reference, + but makes assignment futile. Use instead. + + + Note that is not required to be the field's declaring type. It can be a parent class (including ), + implemented interface, or a derived class of the field's declaring type ("instanceOfT is FieldDeclaringType" must be possible). + Specifically, must be assignable from OR to the field's declaring type. + Technically, this allows Nullable, although Nullable is only relevant for structs, and since only static fields of structs + are allowed for this delegate, and the instance passed to such a delegate is ignored, this hardly matters. + + + Similarly, is not required to be the field's field type, unless that type is a non-enum value type. + It can be a parent class (including object) or implemented interface of the field's field type. It cannot be a derived class. + This variance is not allowed for value types, since that would require boxing/unboxing, which is not allowed for ref values. + Special case for enum types: can also be the underlying integral type of the enum type. + Specifically, for reference types, must be assignable from + the field's field type; for non-enum value types, must be exactly the field's field type; for enum types, + must be either the field's field type or the underyling integral type of that field type. + + + This delegate supports static fields, even those defined in structs, for legacy reasons. + For such static fields, is effectively ignored. + Consider using (and StaticFieldRefAccess methods that return it) instead for static fields. + + + + + + Creates a field reference delegate for an instance field of a class + The class that defines the instance field, or derived class of this type + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable delegate + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates an instance field reference for a specific instance of a class + The class that defines the instance field, or derived class of this type + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The name of the field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance. + If you need to access a field's value for potentially multiple instances, use instead. + FieldRefAccess<T, F>(instance, fieldName) is functionally equivalent to FieldRefAccess<T, F>(fieldName)(instance). + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct) + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + + The type that defines the field, or derived class of this type; must not be a struct type unless the field is static + + The name of the field + + A readable/assignable delegate with T=object + (for static fields, the instance delegate parameter is ignored) + + + + This method is meant for cases where the given type is only known at runtime and thus can't be used as a type parameter T + in e.g. . + + + This method supports static fields, even those defined in structs, for legacy reasons. + Consider using (and other overloads) instead for static fields. + + + + + + Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct) + type of the field + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A readable/assignable delegate with T=object + + + Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct) + + An arbitrary type if the field is static; otherwise the class that defines the field, or a parent class (including ), + implemented interface, or derived class of this type ("instanceOfT is FieldDeclaringType" must be possible) + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + This method is meant for cases where the field has already been obtained, avoiding the field searching cost in + e.g. . + + + This method supports static fields, even those defined in structs, for legacy reasons. + For such static fields, is effectively ignored. + Consider using (and other overloads) instead for static fields. + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates a field reference for an instance field of a class + + The type that defines the field; or a parent class (including ), implemented interface, or derived class of this type + ("instanceOfT is FieldDeclaringType" must be possible) + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained. + If you need to access a field's value for potentially multiple instances, use instead. + FieldRefAccess<T, F>(instance, fieldInfo) is functionally equivalent to FieldRefAccess<T, F>(fieldInfo)(instance). + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + A readable/assignable reference delegate to an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + A reference to the runtime instance to access the field + A readable/assignable reference to the field + + + + Creates a field reference delegate for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable delegate + + + + Creates an instance field reference for a specific instance of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The name of the field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance. + If you need to access a field's value for potentially multiple instances, use instead. + StructFieldRefAccess<T, F>(ref instance, fieldName) is functionally equivalent to StructFieldRefAccess<T, F>(fieldName)(ref instance). + + + + + + Creates a field reference delegate for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + This method is meant for cases where the field has already been obtained, avoiding the field searching cost in + e.g. . + + + + + + Creates a field reference for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained. + If you need to access a field's value for potentially multiple instances, use instead. + StructFieldRefAccess<T, F>(ref instance, fieldInfo) is functionally equivalent to StructFieldRefAccess<T, F>(fieldInfo)(ref instance). + + + + + + A readable/assignable reference delegate to a static field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + A readable/assignable reference to the field + + + + Creates a static field reference + The type (can be class or struct) the field is defined in + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable reference to the field + + + + Creates a static field reference + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The type (can be class or struct) the field is defined in + The name of the field + A readable/assignable reference to the field + + + + Creates a static field reference + The type of the field + The member in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + A readable/assignable reference to the field + + + + Creates a static field reference + An arbitrary type (by convention, the type the field is defined in) + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable reference to the field + + The type parameter is only used in exception messaging and to distinguish between this method overload + and the overload (which returns a rather than a reference). + + + + + Creates a static field reference delegate + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + + Creates a delegate to a given method + The delegate Type + The method to create a delegate from. + + Only applies for instance methods. If null (default), returned delegate is an open (a.k.a. unbound) instance delegate + where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound) + instance delegate where the delegate invocation always applies to the given . + + + Only applies for instance methods. If true (default) and is virtual, invocation of the delegate + calls the instance method virtually (the instance type's most-derived/overriden implementation of the method is called); + else, invocation of the delegate calls the exact specified (this is useful for calling base class methods) + Note: if false and is an interface method, an ArgumentException is thrown. + + A delegate of given to given + + + Delegate invocation is more performant and more convenient to use than + at a one-time setup cost. + + + Works for both type of static and instance methods, both open and closed (a.k.a. unbound and bound) instance methods, + and both class and struct methods. + + + + + + Creates a delegate to a given method + The delegate Type + The method in the form TypeFullName:MemberName, where TypeFullName matches the form recognized by Type.GetType like Some.Namespace.Type. + + Only applies for instance methods. If null (default), returned delegate is an open (a.k.a. unbound) instance delegate + where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound) + instance delegate where the delegate invocation always applies to the given . + + + Only applies for instance methods. If true (default) and is virtual, invocation of the delegate + calls the instance method virtually (the instance type's most-derived/overriden implementation of the method is called); + else, invocation of the delegate calls the exact specified (this is useful for calling base class methods) + Note: if false and is an interface method, an ArgumentException is thrown. + + A delegate of given to given + + + Delegate invocation is more performant and more convenient to use than + at a one-time setup cost. + + + Works for both type of static and instance methods, both open and closed (a.k.a. unbound and bound) instance methods, + and both class and struct methods. + + + + + + Creates a delegate for a given delegate definition, attributed with [] + The delegate Type, attributed with [] + + Only applies for instance methods. If null (default), returned delegate is an open (a.k.a. unbound) instance delegate + where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound) + instance delegate where the delegate invocation always applies to the given . + + A delegate of given to the method specified via [] + attributes on + + This calls with the method and virtualCall arguments + determined from the [] attributes on , + and the given (for closed instance delegates). + + + + + Returns who called the current method + The calling method/constructor (excluding the caller) + + + + Rethrows an exception while preserving its stack trace (throw statement typically clobbers existing stack traces) + The exception to rethrow + + + + True if the current runtime is based on Mono, false otherwise (.NET) + + + + True if the current runtime is .NET Framework, false otherwise (.NET Core or Mono, although latter isn't guaranteed) + + + + True if the current runtime is .NET Core, false otherwise (Mono or .NET Framework) + + + + Throws a missing member runtime exception + The type that is involved + A list of names + + + + Gets default value for a specific type + The class/type + The default value + + + + Creates an (possibly uninitialized) instance of a given type + The class/type + The new instance + + + + Creates an (possibly uninitialized) instance of a given type + The class/type + The new instance + + + + + A cache for the or similar Add methods for different types. + + + + Makes a deep copy of any object + The type of the instance that should be created; for legacy reasons, this must be a class or interface + The original object + A copy of the original object but of type T + + + + Makes a deep copy of any object + The type of the instance that should be created + The original object + [out] The copy of the original object + Optional value transformation function (taking a field name and src/dst instances) + The optional path root to start with + + + + Makes a deep copy of any object + The original object + The type of the instance that should be created + Optional value transformation function (taking a field name and src/dst instances) + The optional path root to start with + The copy of the original object + + + + Tests if a type is a struct + The type + True if the type is a struct + + + + Tests if a type is a class + The type + True if the type is a class + + + + Tests if a type is a value type + The type + True if the type is a value type + + + + Tests if a type is an integer type + The type + True if the type represents some integer + + + + Tests if a type is a floating point type + The type + True if the type represents some floating point + + + + Tests if a type is a numerical type + The type + True if the type represents some number + + + + Tests if a type is void + The type + True if the type is void + + + + Test whether an instance is of a nullable type + Type of instance + An instance to test + True if instance is of nullable type, false if not + + + + Tests whether a type or member is static, as defined in C# + The type or member + True if the type or member is static + + + + Tests whether a type is static, as defined in C# + The type + True if the type is static + + + + Tests whether a property is static, as defined in C# + The property + True if the property is static + + + + Tests whether an event is static, as defined in C# + The event + True if the event is static + + + + Calculates a combined hash code for an enumeration of objects + The objects + The hash code + + + + A CodeInstruction match + + + The name of the match + + + The matched opcodes + + + The matched operands + + + The jumps from the match + + + The jumps to the match + + + The match predicate + + + Creates a code match + The optional opcode + The optional operand + The optional name + + + + Creates a code match that calls a method + The lambda expression using the method + The optional name + + + + Creates a code match that calls a method + The lambda expression using the method + The optional name + + + + Creates a code match + The CodeInstruction + An optional name + + + + Creates a code match + The predicate + An optional name + + + + Returns a string that represents the match + A string representation + + + + A CodeInstruction matcher + + + The current position + The index or -1 if out of bounds + + + + Gets the number of code instructions in this matcher + The count + + + + Checks whether the position of this CodeMatcher is within bounds + True if this CodeMatcher is valid + + + + Checks whether the position of this CodeMatcher is outside its bounds + True if this CodeMatcher is invalid + + + + Gets the remaining code instructions + The remaining count + + + + Gets the opcode at the current position + The opcode + + + + Gets the operand at the current position + The operand + + + + Gets the labels at the current position + The labels + + + + Gets the exception blocks at the current position + The blocks + + + + Creates an empty code matcher + + + Creates a code matcher from an enumeration of instructions + The instructions (transpiler argument) + An optional IL generator + + + + Makes a clone of this instruction matcher + A copy of this matcher + + + + Gets instructions at the current position + The instruction + + + + Gets instructions at the current position with offset + The offset + The instruction + + + + Gets all instructions + A list of instructions + + + + Gets all instructions as an enumeration + A list of instructions + + + + Gets some instructions counting from current position + Number of instructions + A list of instructions + + + + Gets all instructions within a range + The start index + The end index + A list of instructions + + + + Gets all instructions within a range (relative to current position) + The start offset + The end offset + A list of instructions + + + + Gets a list of all distinct labels + The instructions (transpiler argument) + A list of Labels + + + + Reports a failure + The method involved + The logger + True if current position is invalid and error was logged + + + + Throw an InvalidOperationException if current state is invalid (position out of bounds / last match failed) + Explanation of where/why the exception was thrown that will be added to the exception message + The same code matcher + + + + Throw an InvalidOperationException if current state is invalid (position out of bounds / last match failed), + or if the matches do not match at current position + Explanation of where/why the exception was thrown that will be added to the exception message + Some code matches + The same code matcher + + + + Throw an InvalidOperationException if current state is invalid (position out of bounds / last match failed), + or if the matches do not match at any point between current position and the end + Explanation of where/why the exception was thrown that will be added to the exception message + Some code matches + The same code matcher + + + + Throw an InvalidOperationException if current state is invalid (position out of bounds / last match failed), + or if the matches do not match at any point between current position and the start + Explanation of where/why the exception was thrown that will be added to the exception message + Some code matches + The same code matcher + + + + Throw an InvalidOperationException if current state is invalid (position out of bounds / last match failed), + or if the check function returns false + Explanation of where/why the exception was thrown that will be added to the exception message + Function that checks validity of current state. If it returns false, an exception is thrown + The same code matcher + + + + Sets an instruction at current position + The instruction to set + The same code matcher + + + + Sets instruction at current position and advances + The instruction + The same code matcher + + + + Sets opcode and operand at current position + The opcode + The operand + The same code matcher + + + + Sets opcode and operand at current position and advances + The opcode + The operand + The same code matcher + + + + Sets opcode at current position and advances + The opcode + The same code matcher + + + + Sets operand at current position and advances + The operand + The same code matcher + + + + Creates a label at current position + [out] The label + The same code matcher + + + + Creates a label at a position + The position + [out] The new label + The same code matcher + + + + Creates a label at a position + The offset + [out] The new label + The same code matcher + + + + Adds an enumeration of labels to current position + The labels + The same code matcher + + + + Adds an enumeration of labels at a position + The position + The labels + The same code matcher + + + + Sets jump to + Branch instruction + Destination for the jump + [out] The created label + The same code matcher + + + + Inserts some instructions + The instructions + The same code matcher + + + + Inserts an enumeration of instructions + The instructions + The same code matcher + + + + Inserts a branch + The branch opcode + Branch destination + The same code matcher + + + + Inserts some instructions and advances the position + The instructions + The same code matcher + + + + Inserts an enumeration of instructions and advances the position + The instructions + The same code matcher + + + + Inserts a branch and advances the position + The branch opcode + Branch destination + The same code matcher + + + + Removes current instruction + The same code matcher + + + + Removes some instruction from current position by count + Number of instructions + The same code matcher + + + + Removes the instructions in a range + The start + The end + The same code matcher + + + + Removes the instructions in a offset range + The start offset + The end offset + The same code matcher + + + + Advances the current position + The offset + The same code matcher + + + + Moves the current position to the start + The same code matcher + + + + Moves the current position to the end + The same code matcher + + + + Searches forward with a predicate and advances position + The predicate + The same code matcher + + + + Searches backwards with a predicate and reverses position + The predicate + The same code matcher + + + + Matches forward and advances position to beginning of matching sequence + Some code matches + The same code matcher + + + + Matches forward and advances position to ending of matching sequence + Some code matches + The same code matcher + + + + Matches backwards and reverses position to beginning of matching sequence + Some code matches + The same code matcher + + + + Matches backwards and reverses position to ending of matching sequence + Some code matches + The same code matcher + + + + Repeats a match action until boundaries are met + The match action + An optional action that is executed when no match is found + The same code matcher + + + + Gets a match by its name + The match name + An instruction + + + + General extensions for common cases + + + + Joins an enumeration with a value converter and a delimiter to a string + The inner type of the enumeration + The enumeration + An optional value converter (from T to string) + An optional delimiter + The values joined into a string + + + + Converts an array of types (for example methods arguments) into a human readable form + The array of types + A human readable description including brackets + + + + A full description of a type + The type + A human readable description + + + + A a full description of a method or a constructor without assembly details but with generics + The method/constructor + A human readable description + + + + A helper converting parameter infos to types + The array of parameter infos + An array of types + + + + A helper to access a value via key from a dictionary + The key type + The value type + The dictionary + The key + The value for the key or the default value (of T) if that key does not exist + + + + A helper to access a value via key from a dictionary with extra casting + The value type + The dictionary + The key + The value for the key or the default value (of T) if that key does not exist or cannot be cast to T + + + + Escapes Unicode and ASCII non printable characters + The string to convert + The string to convert + A string literal surrounded by + + + + Extensions for + + + + Returns if an is initialized and valid + The + + + + Shortcut for testing whether the operand is equal to a non-null value + The + The value + True if the operand has the same type and is equal to the value + + + + Shortcut for testing whether the operand is equal to a non-null value + The + The value + True if the operand is equal to the value + This is an optimized version of for + + + + Shortcut for code.opcode == opcode && code.OperandIs(operand) + The + The + The operand value + True if the opcode is equal to the given opcode and the operand has the same type and is equal to the given operand + + + + Shortcut for code.opcode == opcode && code.OperandIs(operand) + The + The + The operand value + True if the opcode is equal to the given opcode and the operand is equal to the given operand + This is an optimized version of for + + + + Tests for any form of Ldarg* + The + The (optional) index + True if it matches one of the variations + + + + Tests for Ldarga/Ldarga_S + The + The (optional) index + True if it matches one of the variations + + + + Tests for Starg/Starg_S + The + The (optional) index + True if it matches one of the variations + + + + Tests for any form of Ldloc* + The + The optional local variable + True if it matches one of the variations + + + + Tests for any form of Stloc* + The + The optional local variable + True if it matches one of the variations + + + + Tests if the code instruction branches + The + The label if the instruction is a branch operation or if not + True if the instruction branches + + + + Tests if the code instruction calls the method/constructor + The + The method + True if the instruction calls the method or constructor + + + + Tests if the code instruction loads a constant + The + True if the instruction loads a constant + + + + Tests if the code instruction loads an integer constant + The + The integer constant + True if the instruction loads the constant + + + + Tests if the code instruction loads a floating point constant + The + The floating point constant + True if the instruction loads the constant + + + + Tests if the code instruction loads an enum constant + The + The enum + True if the instruction loads the constant + + + + Tests if the code instruction loads a string constant + The + The string + True if the instruction loads the constant + + + + Tests if the code instruction loads a field + The + The field + Set to true if the address of the field is loaded + True if the instruction loads the field + + + + Tests if the code instruction stores a field + The + The field + True if the instruction stores this field + + + + Adds labels to the code instruction and return it + The + One or several to add + The same code instruction + + + Adds labels to the code instruction and return it + The + An enumeration of + The same code instruction + + + Extracts all labels from the code instruction and returns them + The + A list of + + + Moves all labels from the code instruction to another one + The to move the labels from + The other to move the labels to + The code instruction labels were moved from (now empty) + + + Moves all labels from another code instruction to the current one + The to move the labels to + The other to move the labels from + The code instruction that received the labels + + + Adds ExceptionBlocks to the code instruction and return it + The + One or several to add + The same code instruction + + + Adds ExceptionBlocks to the code instruction and return it + The + An enumeration of + The same code instruction + + + Extracts all ExceptionBlocks from the code instruction and returns them + The + A list of + + + Moves all ExceptionBlocks from the code instruction to another one + The to move the ExceptionBlocks from + The other to move the ExceptionBlocks to + The code instruction blocks were moved from (now empty) + + + Moves all ExceptionBlocks from another code instruction to the current one + The to move the ExceptionBlocks to + The other to move the ExceptionBlocks from + The code instruction that received the blocks + + + General extensions for collections + + + + A simple way to execute code for every element in a collection + The inner type of the collection + The collection + The action to execute + + + + A simple way to execute code for elements in a collection matching a condition + The inner type of the collection + The collection + The predicate + The action to execute + + + + A helper to add an item to a collection + The inner type of the collection + The collection + The item to add + The collection containing the item + + + + A helper to add an item to an array + The inner type of the collection + The array + The item to add + The array containing the item + + + + A helper to add items to an array + The inner type of the collection + The array + The items to add + The array containing the items + + + + General extensions for collections + + + + Tests a class member if it has an IL method body (external methods for example don't have a body) + The member to test + Returns true if the member has an IL body or false if not + + + A file log for debugging + + + + Set this to make Harmony write its log content to this stream + + + + Full pathname of the log file, defaults to a file called harmony.log.txt on your Desktop + + + + The indent character. The default is tab + + + + The current indent level + + + + Changes the indentation level + The value to add to the indentation level + + + + Log a string in a buffered way. Use this method only if you are sure that FlushBuffer will be called + or else logging information is incomplete in case of a crash + The string to log + + + + Logs a list of string in a buffered way. Use this method only if you are sure that FlushBuffer will be called + or else logging information is incomplete in case of a crash + A list of strings to log (they will not be re-indented) + + + + Returns the log buffer and optionally empties it + True to empty the buffer + The buffer. + + + + Replaces the buffer with new lines + The lines to store + + + + Flushes the log buffer to disk (use in combination with LogBuffered) + + + + Log a string directly to disk. Slower method that prevents missing information in case of a crash + The string to log. + + + + Log a string directly to disk if Harmony.DEBUG is true. Slower method that prevents missing information in case of a crash + The string to log. + + + + Resets and deletes the log + + + + Logs some bytes as hex values + The pointer to some memory + The length of bytes to log + + + + A helper class to retrieve reflection info for non-private methods + + + + Given a lambda expression that calls a method, returns the method info + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The generic type + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The generic type + The generic result type + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The lambda expression using the method + The method in the lambda expression + + + + A reflection helper to read and write private elements + The result type defined by GetValue() + + + + Creates a traverse instance from an existing instance + The existing instance + + + + Gets/Sets the current value + The value to read or write + + + + A reflection helper to read and write private elements + + + + Creates a new traverse instance from a class/type + The class/type + A instance + + + + Creates a new traverse instance from a class T + The class + A instance + + + + Creates a new traverse instance from an instance + The object + A instance + + + + Creates a new traverse instance from a named type + The type name, for format see + A instance + + + + Creates a new and empty traverse instance + + + + Creates a new traverse instance from a class/type + The class/type + + + + Creates a new traverse instance from an instance + The object + + + + Gets the current value + The value + + + + Gets the current value + The type of the value + The value + + + + Invokes the current method with arguments and returns the result + The method arguments + The value returned by the method + + + + Invokes the current method with arguments and returns the result + The type of the value + The method arguments + The value returned by the method + + + + Sets a value of the current field or property + The value + The same traverse instance + + + + Gets the type of the current field or property + The type + + + + Moves the current traverse instance to a inner type + The type name + A traverse instance + + + + Moves the current traverse instance to a field + The type name + A traverse instance + + + + Moves the current traverse instance to a field + The type of the field + The type name + A traverse instance + + + + Gets all fields of the current type + A list of field names + + + + Moves the current traverse instance to a property + The type name + Optional property index + A traverse instance + + + + Moves the current traverse instance to a field + The type of the property + The type name + Optional property index + A traverse instance + + + + Gets all properties of the current type + A list of property names + + + + Moves the current traverse instance to a method + The name of the method + The arguments defining the argument types of the method overload + A traverse instance + + + + Moves the current traverse instance to a method + The name of the method + The argument types of the method + The arguments for the method + A traverse instance + + + + Gets all methods of the current type + A list of method names + + + + Checks if the current traverse instance is for a field + True if its a field + + + + Checks if the current traverse instance is for a property + True if its a property + + + + Checks if the current traverse instance is for a method + True if its a method + + + + Checks if the current traverse instance is for a type + True if its a type + + + + Iterates over all fields of the current type and executes a traverse action + Original object + The action receiving a instance for each field + + + + Iterates over all fields of the current type and executes a traverse action + Original object + Target object + The action receiving a pair of instances for each field pair + + + + Iterates over all fields of the current type and executes a traverse action + Original object + Target object + The action receiving a dot path representing the field pair and the instances + + + + Iterates over all properties of the current type and executes a traverse action + Original object + The action receiving a instance for each property + + + + Iterates over all properties of the current type and executes a traverse action + Original object + Target object + The action receiving a pair of instances for each property pair + + + + Iterates over all properties of the current type and executes a traverse action + Original object + Target object + The action receiving a dot path representing the property pair and the instances + + + + A default field action that copies fields to fields + + + + Returns a string that represents the current traverse + A string representation + + + + diff --git a/1.5/Assemblies/RimJobWorldCum.dll b/1.5/Assemblies/RimJobWorldCum.dll new file mode 100644 index 0000000..6fdae43 Binary files /dev/null and b/1.5/Assemblies/RimJobWorldCum.dll differ diff --git a/1.5/Defs/HediffsDef/Hediff_CumController.xml b/1.5/Defs/HediffsDef/Hediff_CumController.xml new file mode 100644 index 0000000..854f8e0 --- /dev/null +++ b/1.5/Defs/HediffsDef/Hediff_CumController.xml @@ -0,0 +1,49 @@ + + + + + Hediff_CumController + rjwcum.Hediff_CumController + + Covered in cum. + false + 0.01 + 1 + + + + + false + false + +
  • + + false +
  • +
  • + 0.3 + + + 0.2 + -0.1 + +
  • +
  • + 0.6 + + + 0.3 + -0.3 + +
  • +
  • + 0.8 + + + -0.1 + -0.5 + +
  • +
    +
    +
    \ No newline at end of file diff --git a/1.5/Defs/HediffsDef/Hediffs_Cum.xml b/1.5/Defs/HediffsDef/Hediffs_Cum.xml new file mode 100644 index 0000000..3a77e61 --- /dev/null +++ b/1.5/Defs/HediffsDef/Hediffs_Cum.xml @@ -0,0 +1,72 @@ + + + + rjwcum.Hediff_Cum + Hediff_Cum + + cum + cum. + cum on {1} + (0.95,0.95,0.95) + false + false + false + false + 1 + 0.001 + + true + + +
  • + +
  • +
  • + 0.25 + +
  • +
  • + 0.5 + +
  • +
  • + 0.8 + +
  • +
    + +
  • + + 1800 + 0.01 +
  • +
    +
    + + + Hediff_Cum + + cum + cum + cum on {1} + (0.95,0.95,0.95) + + + + Hediff_InsectSpunk + Insect spunk. + + insect spunk + insect spunk on {1} + (0.6,0.83,0.35) + + + + Hediff_MechaFluids + Mechanoid fluids. + + mechanoid fluids + mecha fluids on {1} + (0.37,0.71,0.82) + +
    \ No newline at end of file diff --git a/1.5/Defs/JobDefs/Jobs_CleanSelf.xml b/1.5/Defs/JobDefs/Jobs_CleanSelf.xml new file mode 100644 index 0000000..12ae606 --- /dev/null +++ b/1.5/Defs/JobDefs/Jobs_CleanSelf.xml @@ -0,0 +1,10 @@ + + + + + CleanSelf + rjwcum.JobDriver_CleanSelf + cleaning self + true + + \ No newline at end of file diff --git a/1.5/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml b/1.5/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml new file mode 100644 index 0000000..62b7637 --- /dev/null +++ b/1.5/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml @@ -0,0 +1,16 @@ + + + + CleanSelf + + rjwcum.WorkGiver_CleanSelf + Cleaning + clean self + cleaning self + false + 11 + +
  • Manipulation
  • +
    +
    +
    \ No newline at end of file diff --git a/1.5/Languages/English/Keyed/Cum.xml b/1.5/Languages/English/Keyed/Cum.xml new file mode 100644 index 0000000..54ce568 --- /dev/null +++ b/1.5/Languages/English/Keyed/Cum.xml @@ -0,0 +1,15 @@ + + + Debug + + Enable cum on body (Hediffs) + Enables cum hediffs in health tab. + Adjust cum amount on body + All cum applied to pawn bodies will be multiplied by this amount. + Enable cum overlays (Visuals) + Enables cum overlay for pawn drawer(may have conflicts with mods that change pawn appearance and other issues).\nRequires Cum on body option enabled. + Hero manual CleanSelf + Hero pawn will only clean cum from body if manually told so. + DubsBadHygiene block CleanSelf + If DubsBadHygiene installed, pawns will only clean cum from body in buckets, showers, baths, hottubs etc. + \ No newline at end of file diff --git a/1.5/Patches/FacialAnimation_compatibility.xml b/1.5/Patches/FacialAnimation_compatibility.xml new file mode 100644 index 0000000..7a6b70e --- /dev/null +++ b/1.5/Patches/FacialAnimation_compatibility.xml @@ -0,0 +1,20 @@ + + + + +
  • [NL] Facial Animation - WIP
  • +
    + + Always + +
  • + /Defs/FacialAnimation.FaceAnimationDef[defName="Wear" or defName="Wear2" or defName="Wear3"]/targetJobs + Always + +
  • CleanSelf
  • + + +
    +
    +
    +
    \ No newline at end of file diff --git a/1.5/Source/Mod/CumBase.cs b/1.5/Source/Mod/CumBase.cs new file mode 100644 index 0000000..294e079 --- /dev/null +++ b/1.5/Source/Mod/CumBase.cs @@ -0,0 +1,53 @@ +using System; +using HugsLib; +using HugsLib.Settings; +using Verse; + +namespace rjwcum +{ + public class CumBase : ModBase + { + public override string ModIdentifier + { + get + { + return "RJW_Cum"; + } + } + + public static SettingHandle debug; + public static SettingHandle cum_on_body; + public static SettingHandle cum_overlays; + public static SettingHandle cum_on_body_amount; + public static SettingHandle manual_hero_CleanSelf; + public static SettingHandle dubsDBH_block_CleanSelf; + + public override void DefsLoaded() + { + debug = Settings.GetHandle("debug", + Translator.Translate("debug"), + Translator.Translate("debug_desc"), + false); + cum_on_body = Settings.GetHandle("cum_on_body", + Translator.Translate("cum_on_body"), + Translator.Translate("cum_on_body_desc"), + true); + cum_overlays = Settings.GetHandle("cum_overlays", + Translator.Translate("cum_overlays"), + Translator.Translate("cum_overlays_desc"), + true); + cum_on_body_amount = Settings.GetHandle("cum_on_body_amount", + Translator.Translate("cum_on_body_amount"), + Translator.Translate("cum_on_body_amount_desc"), + 1.0f); + manual_hero_CleanSelf = Settings.GetHandle("manual_hero_CleanSelf", + Translator.Translate("manual_hero_CleanSelf"), + Translator.Translate("manual_hero_CleanSelf_desc"), + true); + dubsDBH_block_CleanSelf = Settings.GetHandle("dubsDBH_block_CleanSelf", + Translator.Translate("dubsDBH_block_CleanSelf"), + Translator.Translate("dubsDBH_block_CleanSelf_desc"), + true); + } + } +} diff --git a/1.5/Source/Mod/CumHelper.cs b/1.5/Source/Mod/CumHelper.cs new file mode 100644 index 0000000..dd73f05 --- /dev/null +++ b/1.5/Source/Mod/CumHelper.cs @@ -0,0 +1,622 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using Verse; +using HarmonyLib; +using UnityEngine; +//using Multiplayer.API; +using rjw; + +namespace rjwcum +{ + [StaticConstructorOnStartup] + public static class CumHelper + { + /* + contains many important functions of use to the other classes + */ + + //amount of cum per sex act: + + public static readonly Dictionary splatchAdjust;//saves x (horizontal) and z (vertical) adjustments of texture positiion for each unique combination of bodyType and bodyPart + public static readonly Dictionary layerAdjust;//saves y adjustments (drawing plane) for left/right appendages + bodyPart combinations to hide spunk if pawn looks in the wrong direction + + //structs are used to pack related variables together - used as keys for the dictionaries + public struct key//allows to save all unique combinations of bodyType and bodyPart + { + public readonly BodyTypeDef bodyType; + public readonly BodyPartDef bodyPart; + public key(BodyTypeDef bodyType, BodyPartDef bodyPart) + { + this.bodyType = bodyType; + this.bodyPart = bodyPart; + } + } + + //for the 4 directions, use arrays to store the different adjust for north, east, south, west (in that order) + public struct values + { + public readonly float[] x; + public readonly float[] z; + //public readonly bool over_clothing;//on gentials: hide when clothes are worn - in case of the other body parts it can't be said (for now) if it was added on the clothing or not + public values(float[] xAdjust, float[] zAdjust) + { + x = xAdjust; + z = zAdjust; + //this.over_clothing = over_clothing; + } + } + + + public struct key_layer//used to save left/right appendage + bodyPart combinations + { + public readonly bool left_side; + public readonly BodyPartDef bodyPart; + + public key_layer(bool left_side, BodyPartDef bodyPart) + { + this.left_side = left_side; + this.bodyPart = bodyPart; + } + } + + public struct values_layer//saves the y-adjustments for different body parts and sides -> e.g. allows hiding spunk on the right arm if pawn is looking to the left (aka west) + { + public readonly float[] y; + + public values_layer(float[] yAdjust) + { + y = yAdjust; + } + } + + //get defs of the rjw parts + public static BodyPartDef genitalsDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Genitals")).def; + public static BodyPartDef anusDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Anus")).def; + public static BodyPartDef chestDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Chest")).def; + public static BodyPartDef JawDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Jaw")).def; + public static BodyPartDef NeckDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Neck")).def; + + + static CumHelper() + { + splatchAdjust = new Dictionary(); + //maybe there is a more elegant way to save and load this data, but I don't know about it + + //structure explained: + //1) key: struct consisting of bodyType + bodyPart (= unique key for every combination of bodyType + part) + //2) values: struct containing positioning information (xAdjust: horizontal positioning, yAdjust: vertical positioning, zAdjust: whether to draw above or below pawn + //note: arms, hands, and legs (which are only visible from one direction) values need not be inverted between west and east + + //BodyType Thin + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Arm), new values(new float[] { -0.13f, 0.05f, 0.13f, 0.05f }, new float[] { 0f, 0f, 0f, 0f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Hand), new values(new float[] { -0.12f, 0.15f, 0.12f, 0.15f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, JawDef), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Leg), new values(new float[] { -0.1f, 0.1f, 0.1f, 0.1f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, NeckDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Torso), new values(new float[] { 0f, 0f, 0f, 0f }, new float[] { -0.18f, -0.20f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, genitalsDef), new values(new float[] { 0f, 0.01f, 0f, -0.01f }, new float[] { 0, -0.35f, -0.35f, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, anusDef), new values(new float[] { 0, 0.18f, 0, -0.18f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, chestDef), new values(new float[] { 0f, -0.1f, 0f, 0.1f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Female + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Arm), new values(new float[] { -0.17f, 0f, 0.17f, 0f }, new float[] { 0f, 0f, 0f, 0f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Hand), new values(new float[] { -0.17f, 0.1f, 0.17f, 0.1f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, JawDef), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Leg), new values(new float[] { -0.2f, 0.1f, 0.2f, 0.1f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, NeckDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, genitalsDef), new values(new float[] { 0f, -0.10f, 0f, 0.10f }, new float[] { 0, -0.42f, -0.45f, -0.42f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, anusDef), new values(new float[] { 0, 0.26f, 0, -0.26f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, chestDef), new values(new float[] { 0f, -0.12f, 0f, 0.12f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Male + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Arm), new values(new float[] { -0.21f, 0.05f, 0.21f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Hand), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, JawDef), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, NeckDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, genitalsDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0, -0.35f, -0.42f, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, anusDef), new values(new float[] { 0, 0.17f, 0, -0.17f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, chestDef), new values(new float[] { 0f, -0.16f, 0f, 0.16f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Hulk + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Arm), new values(new float[] { -0.3f, 0.05f, 0.3f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Hand), new values(new float[] { -0.22f, 0.07f, 0.22f, 0.07f }, new float[] { -0.28f, -0.28f, -0.28f, -0.28f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, JawDef), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.5f, -0.5f, -0.5f, -0.5f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, NeckDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.3f, -0.3f, -0.3f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, genitalsDef), new values(new float[] { 0f, -0.02f, 0f, 0.02f }, new float[] { 0, -0.55f, -0.55f, -0.55f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, anusDef), new values(new float[] { 0, 0.35f, 0, -0.35f }, new float[] { -0.5f, -0.5f, 0, -0.5f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, chestDef), new values(new float[] { 0f, -0.22f, 0f, 0.22f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Fat + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Arm), new values(new float[] { -0.3f, 0.05f, 0.3f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Hand), new values(new float[] { -0.32f, 0.07f, 0.32f, 0.07f }, new float[] { -0.28f, -0.28f, -0.28f, -0.28f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, JawDef), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.45f, -0.45f, -0.45f, -0.45f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, NeckDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.15f, 0f, 0.15f }, new float[] { -0.20f, -0.3f, -0.3f, -0.3f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, genitalsDef), new values(new float[] { 0f, -0.25f, 0f, 0.25f }, new float[] { 0, -0.45f, -0.50f, -0.45f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, anusDef), new values(new float[] { 0, 0.35f, 0, -0.35f }, new float[] { -0.5f, -0.4f, 0, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, chestDef), new values(new float[] { 0f, -0.27f, 0f, 0.27f }, new float[] { -0.07f, -0.05f, -0.07f, -0.05f })); + + + //now for the layer/plane adjustments: + layerAdjust = new Dictionary(); + + //left body parts: + //in theory, all body parts not coming in pairs should have the bool as false -> be listed as right, so I wouldn't need to add them here, but it doesn't hurt to be safe + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Arm), new values_layer(new float[] { 0f, -99f, 0f, 0f }));//0.00 = drawn over body (=visible) if the pawn looks in any direction except west, in which case it's hidden (-99) + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Hand), new values_layer(new float[] { 0f, -99f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Leg), new values_layer(new float[] { 0f, -99f, 0f, 0f })); + + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Head), new values_layer(new float[] { 0.02f, 0.02f, 0.02f, 0.02f }));//drawn from all directions, 0.02 = over hair + layerAdjust.Add(new key_layer(true, JawDef), new values_layer(new float[] { -9f, 0.01f, 0.01f, 0.01f }));//0.01 = drawn over head but under hair, only hidden if facing north + layerAdjust.Add(new key_layer(true, NeckDef), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Torso), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, genitalsDef), new values_layer(new float[] { -99f, 0f, 0f, 0f }));//only hidden if facing north + layerAdjust.Add(new key_layer(true, anusDef), new values_layer(new float[] { 0f, 0f, -99f, 0f })); + layerAdjust.Add(new key_layer(true, chestDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + + //right body parts: + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Arm), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Hand), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Leg), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Head), new values_layer(new float[] { 0.02f, 0.02f, 0.02f, 0.02f })); + layerAdjust.Add(new key_layer(false, JawDef), new values_layer(new float[] { -99f, 0.01f, 0.01f, 0.01f })); + layerAdjust.Add(new key_layer(false, NeckDef), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Torso), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, genitalsDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, anusDef), new values_layer(new float[] { 0f, 0f, -99f, 0f })); + layerAdjust.Add(new key_layer(false, chestDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + + } + + //all body parts that cum can theoretically be applied to: + public static List getAllowedBodyParts() + { + List allowedParts = new List(); + + allowedParts.Add(BodyPartDefOf.Arm); + allowedParts.Add(BodyPartDefOf.Hand); + allowedParts.Add(BodyPartDefOf.Leg); + allowedParts.Add(BodyPartDefOf.Head); + allowedParts.Add(JawDef); + allowedParts.Add(NeckDef); + allowedParts.Add(BodyPartDefOf.Torso); + allowedParts.Add(genitalsDef); + allowedParts.Add(anusDef); + allowedParts.Add(chestDef); + + return allowedParts; + } + + //get valid body parts for a specific pawn + public static IEnumerable getAvailableBodyParts(Pawn pawn) + { + //get all non-missing body parts: + IEnumerable bodyParts = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Outside, null, null); + BodyPartRecord anus = pawn.def.race.body.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Anus"));//not found by above function since depth is "inside" + + if (anus != null) + { + bodyParts = bodyParts.AddItem(anus); + } + + //filter for allowed body parts (e.g. no single fingers/toes): + List filterParts = CumHelper.getAllowedBodyParts(); + + IEnumerable filteredParts = bodyParts.Where(item1 => filterParts.Any(item2 => item2.Equals(item1.def))); + return filteredParts; + } + + + public const int CUM_NORMAL = 0; + public const int CUM_INSECT = 1; + public const int CUM_MECHA = 2; + + public static readonly Color color_normal = new Color(0.95f, 0.95f, 0.95f); + public static readonly Color color_insect = new Color(0.6f, 0.83f, 0.35f);//green-yellowish + public static readonly Color color_mecha = new Color(0.37f, 0.71f, 0.82f);//cyan-ish + + //name should be self-explanatory: + public static void cumOn(Pawn receiver, BodyPartRecord bodyPart, float amount = 0.2f, Pawn giver = null, int cumType = CUM_NORMAL) + { + Hediff_Cum hediff; + if (cumType == CUM_NORMAL) + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_Cum, receiver, null); + } + else if (cumType == CUM_INSECT) + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_InsectSpunk, receiver, null); + } + else + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_MechaFluids, receiver, null); + } + + hediff.Severity = amount;//if this body part is already maximally full -> spill over to other parts + + //idea: here, a log entry that can act as source could be linked to the hediff - maybe reuse the playlog entry of rjw: + hediff.cumType = cumType; + + try + { + //error when adding to missing part + receiver.health.AddHediff(hediff, bodyPart, null, null); + } + catch + { + + } + + //Log.Message(xxx.get_pawnname(receiver) + " cum amount" + amount); + //causes significant memory leak, fixx someday + //if (amount > 1f)//spillover in case of very large amounts: just apply hediff a second time + //{ + // Hediff_cum hediff2 = (Hediff_cum)HediffMaker.MakeHediff(hediff.def, receiver, null); + // hediff2.cumType = cumType; + // hediff2.Severity = amount - 1f; + // receiver.health.AddHediff(hediff2, bodyPart, null, null); + //} + + //always also add cumcontroller hediff as manager + receiver.health.AddHediff(HediffDefOf.Hediff_CumController); + } + + //if spunk on one body part reaches a certain level, it can spill over to others, this function returns from where to where + //[SyncMethod] + public static BodyPartDef spillover(BodyPartDef sourcePart) + { + //caution: danger of infinite loop if circular spillover between 2 full parts -> don't define possible circles + BodyPartDef newPart = null; + int sel; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + if (sourcePart == BodyPartDefOf.Torso) + { + sel = Rand.Range(0, 4); + if (sel == 0) + { + newPart = BodyPartDefOf.Arm; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 2) + { + newPart = NeckDef; + } + else if (sel == 3) + { + newPart = chestDef; + } + } + else if (sourcePart == JawDef) + { + sel = Rand.Range(0, 4); + if (sel == 0) + { + newPart = BodyPartDefOf.Head; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + else if (sel == 2) + { + newPart = NeckDef; + } + else if (sel == 3) + { + newPart = chestDef; + } + } + else if (sourcePart == genitalsDef) + { + sel = Rand.Range(0, 2); + if (sel == 0) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + } + else if (sourcePart == anusDef) + { + sel = Rand.Range(0, 2); + if (sel == 0) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + } + else if (sourcePart == chestDef) + { + sel = Rand.Range(0, 3); + if (sel == 0) + { + newPart = BodyPartDefOf.Arm; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + else if (sel == 2) + { + newPart = NeckDef; + } + } + return newPart; + } + + //determines who is the active male (or equivalent) in the exchange and the amount of cum dispensed and where to + //[SyncMethod] + public static void calculateAndApplyCum(SexProps props) + { + if (!CumBase.cum_on_body) return; + Pawn pawn = props.pawn; + Pawn partner = props.partner; + + Pawn giver, receiver; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + + List giverparts; + List pawnparts = pawn.GetGenitalsList(); + List partnerparts = partner != pawn ? partner.GetGenitalsList(): null; // masturbation + + //dispenser of the seed + if (xxx.is_mechanoid(pawn) || Genital_Helper.has_penis_fertile(pawn, pawnparts) || Genital_Helper.has_ovipositorF(pawn, pawnparts)) + { + giver = pawn; + giverparts = pawnparts; + receiver = partner; + } + else if (partner != null && props.isCoreLovin && (xxx.is_mechanoid(partner) || Genital_Helper.has_penis_fertile(partner, partnerparts) || Genital_Helper.has_ovipositorF(partner, partnerparts))) + { + giver = partner; + giverparts = partnerparts; + receiver = pawn; + } + else//female on female or genderless - no cum dispensed; maybe add futa support? + { + return; + } + + //slimes do not waste fluids? + //if (xxx.is_slime(giver)) return; + + //determine entity: + int entityType = CumHelper.CUM_NORMAL; + if (xxx.is_mechanoid(giver)) + { + entityType = CumHelper.CUM_MECHA; + } + else if (xxx.is_insect(giver)) + { + entityType = CumHelper.CUM_INSECT; + } + + //ModLog.Message("giver " + xxx.get_pawnname(giver)); + //ModLog.Message("receiver " + xxx.get_pawnname(receiver)); + //ModLog.Message("Cumtype " + entityType); + + //get pawn genitalia: + BodyPartRecord genitals; + if (xxx.is_mechanoid(giver)) + { + genitals = giver.RaceProps.body.AllParts.Find(x => string.Equals(x.def.defName, "MechGenitals")); + } + else//insects, animals, humans + { + genitals = giver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef); + + } + //no cum without genitals + if (genitals == null) + { + return; + } + + float cumAmount = giver.BodySize; //fallback for mechanoinds and w/e without hediffs + float horniness = 1f; + float ageScale = Math.Min(80 / SexUtility.ScaleToHumanAge(giver), 1.0f);//calculation lifted from rjw + + if (xxx.is_mechanoid(giver) && giverparts.NullOrEmpty()) + { + //use default above + } + else if (giverparts.NullOrEmpty()) + return; + else + { + var penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("penis")).InRandomOrder().FirstOrDefault(); + + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorf")).InRandomOrder().FirstOrDefault(); + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorm")).InRandomOrder().FirstOrDefault(); + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("tentacle")).InRandomOrder().FirstOrDefault(); + + if (penisHediff != null) + { + cumAmount = penisHediff.Severity * giver.BodySize; + + CompHediffBodyPart chdf = penisHediff.TryGetComp(); + if (chdf != null) + { + if (chdf.FluidAmmount != 0) + cumAmount = chdf.FluidAmmount * chdf.FluidModifier; + } + //ModLog.Message("cumAmount base " + cumAmount); + + Need sexNeed = giver?.needs?.AllNeeds.Find(x => string.Equals(x.def.defName, "Sex")); + if (sexNeed != null)//non-humans don't have it - therefore just use the default value + { + horniness = 1f - sexNeed.CurLevel; + } + } + else + { + //something is wrong... vagina? + return; + } + } + + cumAmount *= CumBase.cum_on_body_amount; + //ModLog.Message("cumAmount after cum_on_body_amount_adjust after " + cumAmount); + cumAmount *= horniness; + //ModLog.Message("cumAmount after horniness mod " + cumAmount); + cumAmount *= ageScale; + //ModLog.Message("cumAmount after ageScale mod " + cumAmount); + cumAmount /= 10; + //ModLog.Message("cumAmount final " + cumAmount); + + //TODO: cumHelper Autofellatio + //if no partner -> masturbation, apply some cum on self: + //if (partner == null && sextype == xxx.rjwSextype.Autofellatio) + //{ + // if (!xxx.is_slime(giver)) + // cumHelper.cumOn(giver, BodyPartDefOf.Jaw, cumAmount, giver); + // return; + //} + if (props.sexType == xxx.rjwSextype.Masturbation) + { + if (!xxx.is_slime(giver)) + CumHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver);//pawns are usually not super-messy -> only apply 30% + return; + } + else if (receiver != null) + { + List targetParts = new List();//which to apply cum on + IEnumerable availableParts = CumHelper.getAvailableBodyParts(receiver); + BodyPartRecord randomPart;//not always needed + + switch (props.sexType) + { + case rjw.xxx.rjwSextype.Anal: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + break; + case rjw.xxx.rjwSextype.Boobjob: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.chestDef)); + break; + case rjw.xxx.rjwSextype.DoublePenetration: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + case rjw.xxx.rjwSextype.Fingering: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Fisting: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Footjob: + //random part: + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.Handjob: + //random part: + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.Masturbation: + cumAmount *= 2f; + break; + case rjw.xxx.rjwSextype.MechImplant: + //one of the openings: + int random = Rand.Range(0, 3); + if (random == 0) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + } + else if (random == 1) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + } + else if (random == 2) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == JawDef)); + } + break; + case rjw.xxx.rjwSextype.MutualMasturbation: + //random + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.None: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Oral: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == JawDef)); + break; + case rjw.xxx.rjwSextype.Scissoring: + //I guess if it came to here, a male must be involved? + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + case rjw.xxx.rjwSextype.Vaginal: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + } + + if (cumAmount > 0) + { + if (receiver != null && xxx.is_slime(receiver)) + { + //slime absorb cum + //this needs balancing, since cumamount ranges 0-10(?) which is fine for cum/hentai but not very realistic for feeding + //using TransferNutrition for now + //Log.Message("cumAmount " + cumAmount); + //float nutrition_amount = cumAmount/10; + + Need_Food need = need = giver.needs.TryGetNeed(); + if (need == null) + { + //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(pawn) + " doesn't track nutrition in itself, probably shouldn't feed the others"); + return; + } + + if (receiver?.needs?.TryGetNeed() != null) + { + //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(partner) + " can receive"); + float nutrition_amount = Math.Min(need.MaxLevel / 15f, need.CurLevel); //body size is taken into account implicitly by need.MaxLevel + receiver.needs.food.CurLevel += nutrition_amount; + } + } + else + { + CumHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver, entityType);//cum on self - smaller amount + if (receiver != null) + foreach (BodyPartRecord bpr in targetParts) + { + if (bpr != null) + { + CumHelper.cumOn(receiver, bpr, cumAmount, giver, entityType);//cum on partner + } + } + } + } + } + } + + } +} diff --git a/1.5/Source/Mod/DefOf/HediffDefOf.cs b/1.5/Source/Mod/DefOf/HediffDefOf.cs new file mode 100644 index 0000000..46e8255 --- /dev/null +++ b/1.5/Source/Mod/DefOf/HediffDefOf.cs @@ -0,0 +1,17 @@ +using RimWorld; +using Verse; + +namespace rjwcum +{ + [DefOf] + public static class HediffDefOf + { + public static HediffDef Hediff_Cum;//for humans & animals + public static HediffDef Hediff_InsectSpunk; + public static HediffDef Hediff_MechaFluids; + + public static HediffDef Hediff_CumController;//cum hediff manager + + } + +} diff --git a/1.5/Source/Mod/DefOf/JobDefOf.cs b/1.5/Source/Mod/DefOf/JobDefOf.cs new file mode 100644 index 0000000..f8569e6 --- /dev/null +++ b/1.5/Source/Mod/DefOf/JobDefOf.cs @@ -0,0 +1,11 @@ +using RimWorld; +using Verse; + +namespace rjwcum +{ + [DefOf] + public static class JobDefOf + { + public static JobDef CleanSelf; + } +} diff --git a/1.5/Source/Mod/Hediffs/Hediff_Cum.cs b/1.5/Source/Mod/Hediffs/Hediff_Cum.cs new file mode 100644 index 0000000..92595dc --- /dev/null +++ b/1.5/Source/Mod/Hediffs/Hediff_Cum.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Verse; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + public class Hediff_Cum : HediffWithComps + { + public int cumType = CumHelper.CUM_NORMAL;//-> different colors + + public string giverName = null;//not utilized right now, maybe in the future save origin of the cum + + public override string LabelInBrackets + { + get + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(base.LabelInBrackets); + if (this.sourceHediffDef != null) + { + if (stringBuilder.Length != 0) + { + stringBuilder.Append(", "); + } + stringBuilder.Append(this.sourceHediffDef.label); + } + else if (this.sourceDef != null) + { + if (stringBuilder.Length != 0) + { + stringBuilder.Append(", "); + } + stringBuilder.Append(this.sourceLabel); + if (this.sourceBodyPartGroup != null) + { + stringBuilder.Append(" "); + stringBuilder.Append(this.sourceBodyPartGroup.LabelShort); + } + } + return stringBuilder.ToString(); + } + } + + + public override string SeverityLabel + { + get + { + if (this.Severity == 0f) + { + return null; + } + return this.Severity.ToString("F1"); + } + } + + //[SyncMethod] + public override bool TryMergeWith(Hediff other) + { + //if a new cum hediff is added to the same body part, they are combined. if severity reaches more than 1, spillover to other body parts occurs + + Hediff_Cum hediff_cum = other as Hediff_Cum; + if (hediff_cum != null && hediff_cum.def == this.def && hediff_cum.Part == base.Part && this.def.injuryProps.canMerge) + { + cumType = hediff_cum.cumType;//take over new creature color + + float totalAmount = hediff_cum.Severity + this.Severity; + if (totalAmount > 1.0f) + { + BodyPartDef spillOverTo = CumHelper.spillover(this.Part.def);//cumHelper saves valid other body parts for spillover + if (spillOverTo != null) + { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + IEnumerable availableParts = CumHelper.getAvailableBodyParts(pawn);//gets all non missing, valid body parts + IEnumerable filteredParts = availableParts.Where(x => x.def == spillOverTo);//filters again for valid spill target + if (!filteredParts.EnumerableNullOrEmpty()) + { + BodyPartRecord spillPart = null; + spillPart = filteredParts.RandomElement();//then pick one + if (spillPart != null) + { + CumHelper.cumOn(pawn, spillPart, totalAmount - this.Severity, null, cumType); + } + } + } + } + + return (base.TryMergeWith(other)); + + } + return (false); + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref cumType, "cumType", CumHelper.CUM_NORMAL); + + if (Scribe.mode == LoadSaveMode.PostLoadInit && base.Part == null) + { + //Log.Error("Hediff_cum has null part after loading.", false); + this.pawn.health.hediffSet.hediffs.Remove(this); + return; + } + } + + //handles the icon in the health tab and its color + public override TextureAndColor StateIcon + { + get + { + TextureAndColor tex = TextureAndColor.None; + Color color = Color.white; + switch (cumType) + { + case CumHelper.CUM_NORMAL: + color = CumHelper.color_normal; + break; + case CumHelper.CUM_INSECT: + color = CumHelper.color_insect; + break; + case CumHelper.CUM_MECHA: + color = CumHelper.color_mecha; + break; + } + + Texture2D tex2d = CumTextures.CumIcon_little; + switch (this.CurStageIndex) + { + case 0: + tex2d = CumTextures.CumIcon_little; + break; + case 1: + tex2d = CumTextures.CumIcon_some; + break; + case 2: + tex2d = CumTextures.CumIcon_dripping; + break; + case 3: + tex2d = CumTextures.CumIcon_drenched; + break; + } + + tex = new TextureAndColor(tex2d, color); + + return tex; + } + } + + } +} diff --git a/1.5/Source/Mod/Hediffs/Hediff_CumController.cs b/1.5/Source/Mod/Hediffs/Hediff_CumController.cs new file mode 100644 index 0000000..ca47016 --- /dev/null +++ b/1.5/Source/Mod/Hediffs/Hediff_CumController.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Verse; +using RimWorld; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + class Hediff_CumController : HediffWithComps + { + /* + Whenever cum is applied, this hediff is also added to the pawn. + Since there is always only a single hediff of this type on the pawn, it serves as master controller, adding up the individual cum hediffs, applying debuffs and drawing overlays + */ + + private static readonly float cumWeight = 0.2f;//how much individual cum_hediffs contribute to the overall bukkake severity + List hediffs_cum; + Dictionary splatches; + + public override void ExposeData() + { + base.ExposeData(); + //Scribe_Values.Look>(ref splatches, "splatches", new Dictionary()); - causes errors when loading. for now, just make a new dictionary + splatches = new Dictionary();//instead of loading, just recreate anew + hediffs_cum = new List(); + } + + public override void PostMake() + { + base.PostMake(); + splatches = new Dictionary(); + } + + public override void PostTick() + { + if (pawn.RaceProps.Humanlike)//for now, only humans are supported + { + hediffs_cum = this.pawn.health.hediffSet.hediffs.FindAll(x => (x.def == HediffDefOf.Hediff_Cum || x.def == HediffDefOf.Hediff_InsectSpunk || x.def == HediffDefOf.Hediff_MechaFluids)); + float Level = CalculateLevel();//sum of severity of all the cum hediffs x cumWeight + this.Severity = Level; + bool updatePortrait = false; + + //loop through all cum hediffs, add missing ones to dictionary + for (int i = 0; i < hediffs_cum.Count(); i++) + { + Hediff_Cum h = (Hediff_Cum)hediffs_cum[i]; + string ID = h.GetUniqueLoadID();//unique ID for each hediff + if (!splatches.ContainsKey(ID))//if it isn't here yet, make new object + { + updatePortrait = true; + bool leftSide = h.Part.Label.Contains("left") ? true : false;//depending on whether the body part is left or right, drawing-offset on x-aixs may be inverted + + splatches[ID] = new CumSplatch(h, pawn.story.bodyType, h.Part.def, leftSide, h.cumType); + } + } + + + + //remove splatch objects once their respective cum hediff is gone + List removeKeys = new List(); + foreach (string key in splatches.Keys) + { + CumSplatch s = splatches[key]; + + if (!hediffs_cum.Contains(s.hediff_cum)) + { + removeKeys.Add(key); + updatePortrait = true; + } + } + //loop over and remove elements that should be destroyed: + foreach (string key in removeKeys) + { + CumSplatch s = splatches[key]; + splatches.Remove(key); + } + + if (updatePortrait)//right now, portraits are only updated when a completely new cum hediff is added or an old one removed - maybe that should be done more frequently + { + PortraitsCache.SetDirty(pawn); + } + } + } + + //called from the PawnWoundDrawer (see HarmonyPatches) + public void DrawCum(Vector3 drawLoc, Quaternion quat, bool forPortrait, float angle, bool inBed = false) + { + Rot4 bodyFacing = pawn.Rotation; + int facingDir = bodyFacing.AsInt;//0: north, 1:east, 2:south, 3:west + foreach (string key in splatches.Keys) + { + CumSplatch s = splatches[key]; + s.Draw(drawLoc, quat, forPortrait, facingDir, angle, inBed); + } + } + + //new Hediff_CumController added to pawn -> just combine the two + public override bool TryMergeWith(Hediff other) + { + if (other == null || other.def != this.def) + { + return false; + } + return true; + } + + private float CalculateLevel() + { + float num = 0f; + for (int i = 0; i < hediffs_cum.Count; i++) + { + num += hediffs_cum[i].Severity * cumWeight; + } + return num; + } + + //class for handling drawing of the individual splatches + private class CumSplatch + { + public readonly Hediff_Cum hediff_cum; + public readonly Material cumMaterial; + public readonly BodyPartDef bodyPart; + private bool mirrorMesh; + + private const float maxSize = 0.20f;//1.0 = 1 tile + private const float minSize = 0.05f; + + //data taken from CumHelper.cs: + private readonly float[] xAdjust; + private readonly float[] zAdjust; + private readonly float[] yAdjust; + + public CumSplatch(Hediff_Cum hediff, BodyTypeDef bodyType, BodyPartDef bodyPart, bool leftSide = false, int cumType = CumHelper.CUM_NORMAL) + { + hediff_cum = hediff; + cumMaterial = new Material(CumTextures.pickRandomSplatch());//needs to create new material in order to allow for different colors + cumMaterial.SetTextureScale("_MainTex", new Vector2(-1, 1)); + this.bodyPart = bodyPart; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + + //set color: + switch (cumType) + { + case CumHelper.CUM_NORMAL: + cumMaterial.color = CumHelper.color_normal; + break; + case CumHelper.CUM_INSECT: + cumMaterial.color = CumHelper.color_insect; + break; + case CumHelper.CUM_MECHA: + cumMaterial.color = CumHelper.color_mecha; + break; + } + + //if (!MP.enabled) + mirrorMesh = (Rand.Value > 0.5f);//in 50% of the cases, flip mesh horizontally for more variance + + //x,y,z adjustments to draw splatches over the approximately correct locations; values stored in Cum helper - accessed by unique combinations of bodyTypes and bodyParts + CumHelper.key k = new CumHelper.key(bodyType, bodyPart); + if (CumHelper.splatchAdjust.Keys.Contains(k)) + { + CumHelper.values helperValues = CumHelper.splatchAdjust[k]; + + //invert, x-adjust (horizontal) depending on left/right body side: + if (!leftSide) + { + float[] xAdjTemp = new float[4]; + for (int i = 0; i < xAdjTemp.Length; i++) + { + xAdjTemp[i] = helperValues.x[i] * -1f; + } + xAdjust = xAdjTemp; + } + else + { + xAdjust = helperValues.x; + } + + zAdjust = helperValues.z;//vertical adjustment + + } + else//fallback in the the key can't be found + { + //if (RJWSettings.DevMode) + //{ + // ModLog.Message("created cum splatch for undefined body type or part. BodyType: " + bodyType + " , BodyPart: " + bodyPart); + //} + xAdjust = new float[] { 0f, 0f, 0f, 0f }; + zAdjust = new float[] { 0f, 0f, 0f, 0f }; + } + + + //y adjustments: plane/layer of drawing, > 0 -> above certain objects, < 0 -> below + CumHelper.key_layer k2 = new CumHelper.key_layer(leftSide, bodyPart); + + if (CumHelper.layerAdjust.Keys.Contains(k2)) + { + CumHelper.values_layer helperValues_layer = CumHelper.layerAdjust[k2]; + yAdjust = helperValues_layer.y; + } + else + { + yAdjust = new float[] { 0.02f, 0.02f, 0.02f, 0.02f };//over body in every direction + } + + } + + public void Draw(Vector3 drawPos, Quaternion quat, bool forPortrait, int facingDir = 0, float angle = 0,bool inBed=false) + { + if (inBed) + { + if (this.bodyPart != CumHelper.JawDef && this.bodyPart != BodyPartDefOf.Head)//when pawn is in bed (=bed with sheets), only draw cum on head + { + return; + } + } + + //these two create new mesh instance and never destroying it, filling ram and crashing + //float size = minSize+((maxSize-minSize)*hediff_cum.Severity); + //mesh = MeshMakerPlanes.NewPlaneMesh(size); + + //use core MeshPool.plane025 instead + + //if (mirrorMesh)//horizontal flip + //{ + //mesh = flipMesh(mesh); + //} + + //rotation: + if (angle == 0)//normal situation (pawn standing upright) + { + drawPos.x += xAdjust[facingDir]; + drawPos.z += zAdjust[facingDir]; + } + else//if downed etc, more complex calculation becomes necessary + { + float radian = angle / 180 * (float)Math.PI; + radian = -radian; + drawPos.x += Mathf.Cos(radian) * xAdjust[hediff_cum.pawn.Rotation.AsInt] - Mathf.Sin(radian) * zAdjust[facingDir];//facingDir doesn't appear to be chosen correctly in all cases + drawPos.z += Mathf.Cos(radian) * zAdjust[hediff_cum.pawn.Rotation.AsInt] + Mathf.Sin(radian) * xAdjust[facingDir]; + } + + //drawPos.y += yAdjust[facingDir];// 0.00: over body; 0.01: over body but under face, 0.02: over face, but under hair, -99 = "never" visible + drawPos.y += yAdjust[facingDir]; + + GenDraw.DrawMeshNowOrLater(MeshPool.plane025, drawPos, quat, cumMaterial, forPortrait); + } + + //flips mesh UV horizontally, thereby mirroring the texture + private Mesh flipMesh(Mesh meshToFlip) + { + var uvs = meshToFlip.uv; + if (uvs.Length != 4) + { + return (meshToFlip); + } + for (var i = 0; i < uvs.Length; i++) + { + if (Mathf.Approximately(uvs[i].x, 1.0f)) + uvs[i].x = 0.0f; + else + uvs[i].x = 1.0f; + } + meshToFlip.uv = uvs; + return (meshToFlip); + } + } + } +} diff --git a/1.5/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs b/1.5/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs new file mode 100644 index 0000000..d1d4ce3 --- /dev/null +++ b/1.5/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs @@ -0,0 +1,53 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; +using Verse.AI; + +namespace rjwcum +{ + class JobDriver_CleanSelf : JobDriver + { + float cleanAmount = 1f;//severity of a single cumHediff removed per cleaning-round; 1f = remove entirely + int cleaningTime = 120;//ticks - 120 = 2 real seconds, 3 in-game minutes + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return pawn.Reserve(pawn, job, 1, -1, null, errorOnFailed); + } + + protected override IEnumerable MakeNewToils() + { + this.FailOn(delegate + { + List hediffs = pawn.health.hediffSet.hediffs; + return !hediffs.Exists(x => x.def == HediffDefOf.Hediff_CumController);//fail if cum disappears - means that also all the cum is gone + }); + Toil cleaning = Toils_General.Wait(cleaningTime, TargetIndex.None);//duration of + cleaning.WithProgressBarToilDelay(TargetIndex.A); + + yield return cleaning; + yield return new Toil() + { + initAction = delegate () + { + //get one of the cum hediffs, reduce its severity + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_Cum || x.def == HediffDefOf.Hediff_InsectSpunk || x.def == HediffDefOf.Hediff_MechaFluids)); + if (hediff != null) + { + if (hediff.Severity >= 0.5) + { + if (hediff.def == HediffDefOf.Hediff_InsectSpunk) + { + Thing jelly = ThingMaker.MakeThing(ThingDefOf.InsectJelly); + jelly.SetForbidden(true, false); + GenPlace.TryPlaceThing(jelly, pawn.PositionHeld, pawn.MapHeld, ThingPlaceMode.Near); + } + } + hediff.Severity -= cleanAmount; + } + } + }; + yield break; + } + } +} diff --git a/1.5/Source/Mod/Patch_AddCumOnOrgasm.cs b/1.5/Source/Mod/Patch_AddCumOnOrgasm.cs new file mode 100644 index 0000000..a348076 --- /dev/null +++ b/1.5/Source/Mod/Patch_AddCumOnOrgasm.cs @@ -0,0 +1,66 @@ +using Verse; +using HarmonyLib; +using rjw; +using System; +//using Multiplayer.API; + +namespace rjwcum +{ + /// + ///apply cum to pawn after vanilla sex + /// + [HarmonyPatch(typeof(SexUtility), "Aftersex")] + [StaticConstructorOnStartup] + static class Aftersex_Cum_Apply + { + [HarmonyPostfix] + private static void Aftersex_Cum_Patch(SexProps props) + { + try + { + if (props.isCoreLovin) + if (!props.usedCondom) + { + CumHelper.calculateAndApplyCum(props); + //SexUtility.CumFilthGenerator(props.pawn); + //SexUtility.CumFilthGenerator(props.partner); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + } + + /// + ///apply cum to pawn after rjw orgasm + /// + [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] + [StaticConstructorOnStartup] + static class Orgasm_Cum_Apply + { + [HarmonyPrefix] + private static bool Orgasm_Cum_Patch(JobDriver_Sex __instance) + { + try + { + if (__instance.sex_ticks > __instance.orgasmstick) //~3s at speed 1 + { + return true; + } + var props = __instance.Sexprops; + if (!props.usedCondom) + { + CumHelper.calculateAndApplyCum(props); + //SexUtility.CumFilthGenerator(props.pawn); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + return true; + } + } +} diff --git a/1.5/Source/Mod/Patch_AddGizmo.cs b/1.5/Source/Mod/Patch_AddGizmo.cs new file mode 100644 index 0000000..e995f01 --- /dev/null +++ b/1.5/Source/Mod/Patch_AddGizmo.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Verse; +using HarmonyLib; +using rjw; +//using Multiplayer.API; + +namespace rjwcum +{ + //adds new gizmo for adding cum for testing + [HarmonyPatch(typeof(Pawn), "GetGizmos")] + class Patch_AddGizmo + { + [HarmonyPriority(99),HarmonyPostfix] + static IEnumerable AddCum_test(IEnumerable __result, Pawn __instance) + { + + foreach (Gizmo entry in __result) + { + yield return entry; + } + + if (Prefs.DevMode )//&& RJWSettings.DevMode && !MP.IsInMultiplayer) + { + Command_Action addCum = new Command_Action(); + addCum.defaultDesc = "AddCumHediff"; + addCum.defaultLabel = "AddCum"; + addCum.action = delegate () + { + AddCum(__instance); + }; + + yield return addCum; + } + } + + //[SyncMethod] + static void AddCum(Pawn pawn) + { + //Log.Message("add cum button is pressed for " + pawn); + + if (!pawn.Dead && pawn.records != null) + { + //get all acceptable body parts: + IEnumerable filteredParts = CumHelper.getAvailableBodyParts(pawn); + + //select random part: + BodyPartRecord randomPart; + //filteredParts.TryRandomElement(out randomPart); + //for testing - choose either genitals or anus: + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + if (Rand.Value > 0.5f) + { + randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.anusDef); + } + else + { + randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.genitalsDef); + } + + if (randomPart != null) + { + CumHelper.cumOn(pawn, randomPart, 0.2f, null, CumHelper.CUM_NORMAL); + } + }; + } + } +} diff --git a/1.5/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs b/1.5/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs new file mode 100644 index 0000000..3ed4168 --- /dev/null +++ b/1.5/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs @@ -0,0 +1,85 @@ +using System; +using HarmonyLib; +using Verse; +using Verse.AI; +using rjw; + +namespace rjwcum +{ + [HarmonyPatch(typeof(JobDriver), "Cleanup")] + internal static class Patch_JobDriver_DubsBadHygiene + { + //not very good solution, some other mod can have same named jobdriver but w/e + + //Dubs Bad Hygiene washing + private readonly static Type JobDriver_useWashBucket = AccessTools.TypeByName("JobDriver_useWashBucket"); + //private readonly static Type JobDriver_washAtCell = AccessTools.TypeByName("JobDriver_washAtCell"); + + private readonly static Type JobDriver_UseHotTub = AccessTools.TypeByName("JobDriver_UseHotTub"); + private readonly static Type JobDriver_takeShower = AccessTools.TypeByName("JobDriver_takeShower"); + private readonly static Type JobDriver_takeBath = AccessTools.TypeByName("JobDriver_takeBath"); + + [HarmonyPostfix] + private static void Cleanup_cum(JobDriver __instance, JobCondition condition) + { + try + { + if (__instance == null) + return; + + if (condition == JobCondition.Succeeded) + { + Do_cleanup_cum(__instance); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + + public static void Do_cleanup_cum(JobDriver __instance) + { + Pawn pawn = __instance.pawn; + + //ModLog.Message("patches_DubsBadHygiene::on_cleanup_driver" + xxx.get_pawnname(pawn)); + + if (xxx.DubsBadHygieneIsActive) + //clear one instance of cum + if ( + __instance.GetType() == JobDriver_useWashBucket// || + //__instance.GetType() == JobDriver_washAtCell + ) + { + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_Cum + || x.def == HediffDefOf.Hediff_InsectSpunk + || x.def == HediffDefOf.Hediff_MechaFluids + )); + if (hediff != null) + { + //ModLog.Message("patches_DubsBadHygiene::" + __instance.GetType() + " clear => " + hediff.Label); + hediff.Severity -= 1f; + } + } + //clear all instance of cum + else if ( + __instance.GetType() == JobDriver_UseHotTub || + __instance.GetType() == JobDriver_takeShower || + __instance.GetType() == JobDriver_takeBath + ) + { + foreach (Hediff hediff in pawn.health.hediffSet.hediffs) + { + if (hediff.def == HediffDefOf.Hediff_Cum || + hediff.def == HediffDefOf.Hediff_InsectSpunk || + hediff.def == HediffDefOf.Hediff_MechaFluids + ) + { + //ModLog.Message("patches_DubsBadHygiene::" + __instance.GetType() + " clear => " + hediff.Label); + hediff.Severity -= 1f; + } + } + } + } + } +} \ No newline at end of file diff --git a/1.5/Source/Mod/Patch_RenderOverBody.cs b/1.5/Source/Mod/Patch_RenderOverBody.cs new file mode 100644 index 0000000..7da14a3 --- /dev/null +++ b/1.5/Source/Mod/Patch_RenderOverBody.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using Verse; +using HarmonyLib; +using UnityEngine; +using System; +using RimWorld; +using static RimWorld.PawnOverlayDrawer; +//using Multiplayer.API; + +namespace rjwcum +{ + + [HarmonyPatch(typeof(RimWorld.PawnOverlayDrawer))] + [HarmonyPatch("RenderPawnOverlay")] + //[HarmonyPatch(new Type[] { typeof(Vector3), typeof(Mesh), typeof(Quaternion), typeof(bool), typeof(PawnOverlayDrawer.OverlayLayer), typeof(Rot4), typeof(bool) })] + [HarmonyPatch(new Type[] { typeof(Matrix4x4), typeof(Mesh), typeof(PawnOverlayDrawer.OverlayLayer), typeof(PawnDrawParms), typeof(bool) })] + class Patch_RenderPawnOverlay + { + [HarmonyPostfix] + static void DrawCum(RimWorld.PawnOverlayDrawer __instance, Vector3 drawLoc, Mesh bodyMesh, Quaternion quat, bool drawNow, PawnOverlayDrawer.OverlayLayer layer, Rot4 pawnRot, bool? overApparel = null) + { + if (!CumBase.cum_overlays) return; + + Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue();//get local variable + + //TODO add support for animals? unlikely as they has weird meshes + //for now, only draw humans + if (pawn.RaceProps.Humanlike) //&& CumOverlayBase.cum_overlays) + { + //find cum hediff. if it exists, use its draw function + List hediffs = pawn.health.hediffSet.hediffs; + if (hediffs.Exists(x => x.def == HediffDefOf.Hediff_CumController)) + { + Hediff_CumController h = hediffs.Find(x => x.def == HediffDefOf.Hediff_CumController) as Hediff_CumController; + + quat.ToAngleAxis(out float angle, out Vector3 axis);//angle changes when pawn is e.g. downed + + //adjustments if the pawn is sleeping in a bed: + bool inBed = false; + Building_Bed building_Bed = pawn.CurrentBed(); + if (building_Bed != null) + { + inBed = !building_Bed.def.building.bed_showSleeperBody; + AltitudeLayer altLayer = (AltitudeLayer)Mathf.Max((int)building_Bed.def.altitudeLayer, 15); + Vector3 vector2 = pawn.Position.ToVector3ShiftedWithAltitude(altLayer); + vector2.y += 0.02734375f+0.01f;//just copied from rimworld code+0.01f + drawLoc.y = vector2.y; + } + + h.DrawCum(drawLoc, quat, layer == PawnOverlayDrawer.OverlayLayer.Head, angle); + } + } + + } + } +} diff --git a/1.5/Source/Mod/RimJobWorldCum.csproj b/1.5/Source/Mod/RimJobWorldCum.csproj new file mode 100644 index 0000000..6722939 --- /dev/null +++ b/1.5/Source/Mod/RimJobWorldCum.csproj @@ -0,0 +1,79 @@ + + + + + Debug + AnyCPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28} + Library + rjwcum + RimJobWorldCum + v4.7.2 + 512 + + + AnyCPU + true + full + false + ..\..\Assemblies\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\Assemblies\ + TRACE + prompt + 4 + + + + ..\packages\Lib.Harmony.2.3.3\lib\net472\0Harmony.dll + False + + + ..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll + False + + + ..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.5\Assemblies\HugsLib.dll + False + + + ..\..\..\..\rjw\1.5\Assemblies\RJW.dll + False + + + + + ..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/1.5/Source/Mod/Textures.cs b/1.5/Source/Mod/Textures.cs new file mode 100644 index 0000000..6ec85f6 --- /dev/null +++ b/1.5/Source/Mod/Textures.cs @@ -0,0 +1,58 @@ +using Verse; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + [StaticConstructorOnStartup] + public static class CumTextures + { + //UI: + public static readonly Texture2D CumIcon_little = ContentFinder.Get("CumIcon_little", true); + public static readonly Texture2D CumIcon_some = ContentFinder.Get("CumIcon_some", true); + public static readonly Texture2D CumIcon_dripping = ContentFinder.Get("CumIcon_dripping", true); + public static readonly Texture2D CumIcon_drenched = ContentFinder.Get("CumIcon_drenched", true); + + //on pawn: + public static readonly Material cumSplatch1 = MaterialPool.MatFrom("splatch_1", ShaderDatabase.Cutout); + public static readonly Material cumSplatch2 = MaterialPool.MatFrom("splatch_2", ShaderDatabase.Cutout); + public static readonly Material cumSplatch3 = MaterialPool.MatFrom("splatch_3", ShaderDatabase.Cutout); + public static readonly Material cumSplatch4 = MaterialPool.MatFrom("splatch_4", ShaderDatabase.Cutout); + public static readonly Material cumSplatch5 = MaterialPool.MatFrom("splatch_5", ShaderDatabase.Cutout); + public static readonly Material cumSplatch6 = MaterialPool.MatFrom("splatch_6", ShaderDatabase.Cutout); + public static readonly Material cumSplatch7 = MaterialPool.MatFrom("splatch_7", ShaderDatabase.Cutout); + public static readonly Material cumSplatch8 = MaterialPool.MatFrom("splatch_8", ShaderDatabase.Cutout); + public static readonly Material cumSplatch9 = MaterialPool.MatFrom("splatch_9", ShaderDatabase.Cutout); + + + //[SyncMethod] + public static Material pickRandomSplatch() + { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + int rand = Rand.Range(0, 8); + switch (rand) + { + case 0: + return cumSplatch1; + case 1: + return cumSplatch2; + case 2: + return cumSplatch3; + case 3: + return cumSplatch4; + case 4: + return cumSplatch5; + case 5: + return cumSplatch6; + case 6: + return cumSplatch7; + case 7: + return cumSplatch8; + case 8: + return cumSplatch9; + } + return null; + } + } +} diff --git a/1.5/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs b/1.5/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs new file mode 100644 index 0000000..533b827 --- /dev/null +++ b/1.5/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs @@ -0,0 +1,76 @@ +using RimWorld; +using Verse; +using Verse.AI; +using rjw; + +namespace rjwcum +{ + public class WorkGiver_CleanSelf : WorkGiver_Scanner + { + public override PathEndMode PathEndMode + { + get + { + return PathEndMode.InteractionCell; + } + } + + public override Danger MaxPathDanger(Pawn pawn) + { + return Danger.Deadly; + } + + public override ThingRequest PotentialWorkThingRequest + { + get + { + return ThingRequest.ForGroup(ThingRequestGroup.Pawn); + } + } + + //conditions for self-cleaning job to be available + public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) + { + if (xxx.DubsBadHygieneIsActive && CumBase.dubsDBH_block_CleanSelf) // selfclean only in shower/bath etc + return false; + + if (pawn != t) + return false; + + if (!pawn.CanReserve(t, 1, -1, null, forced)) + return false; + + if (pawn.IsDesignatedHero()) + { + if (!forced && CumBase.manual_hero_CleanSelf) + { + //ModLog.Message("WorkGiver_CleanSelf::not player interaction for hero, exit"); + return false; + } + if (!pawn.IsHeroOwner()) + { + //ModLog.Message("WorkGiver_CleanSelf::player interaction for not owned hero, exit"); + return false; + } + } + + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_CumController)); + if (hediff == null) + return false; + + int minAge = 3 * 2500;//3 hours in-game must have passed + if (!forced) + if (!(hediff.ageTicks > minAge)) + { + //ModLog.Message("WorkGiver_CleanSelf:: 3 hours in-game must pass to self-clean, exit"); + return false; + } + return true; + } + + public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) + { + return JobMaker.MakeJob(JobDefOf.CleanSelf); + } + } +} diff --git a/1.5/Source/Mod/packages.config b/1.5/Source/Mod/packages.config new file mode 100644 index 0000000..75a6411 --- /dev/null +++ b/1.5/Source/Mod/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/1.5/Source/Properties/AssemblyInfo.cs b/1.5/Source/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..78fe39f --- /dev/null +++ b/1.5/Source/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RimJobWorld Cum")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RimJobWorld Cum")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c2825019-7f0b-456d-85a3-479c1a2a8805")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/1.5/Source/mod.sln b/1.5/Source/mod.sln new file mode 100644 index 0000000..ee41d20 --- /dev/null +++ b/1.5/Source/mod.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RimJobWorldCum", "Mod\RimJobWorldCum.csproj", "{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5A0C2732-36A9-4ACA-807E-019E02C37E10} + EndGlobalSection +EndGlobal diff --git a/1.5/Textures/CumIcon_drenched.png b/1.5/Textures/CumIcon_drenched.png new file mode 100644 index 0000000..842f804 Binary files /dev/null and b/1.5/Textures/CumIcon_drenched.png differ diff --git a/1.5/Textures/CumIcon_dripping.png b/1.5/Textures/CumIcon_dripping.png new file mode 100644 index 0000000..daea570 Binary files /dev/null and b/1.5/Textures/CumIcon_dripping.png differ diff --git a/1.5/Textures/CumIcon_little.png b/1.5/Textures/CumIcon_little.png new file mode 100644 index 0000000..f7abde3 Binary files /dev/null and b/1.5/Textures/CumIcon_little.png differ diff --git a/1.5/Textures/CumIcon_some.png b/1.5/Textures/CumIcon_some.png new file mode 100644 index 0000000..d36e3f1 Binary files /dev/null and b/1.5/Textures/CumIcon_some.png differ diff --git a/1.5/Textures/splatch_1.png b/1.5/Textures/splatch_1.png new file mode 100644 index 0000000..1e930d3 Binary files /dev/null and b/1.5/Textures/splatch_1.png differ diff --git a/1.5/Textures/splatch_2.png b/1.5/Textures/splatch_2.png new file mode 100644 index 0000000..514a2f1 Binary files /dev/null and b/1.5/Textures/splatch_2.png differ diff --git a/1.5/Textures/splatch_3.png b/1.5/Textures/splatch_3.png new file mode 100644 index 0000000..452bc0c Binary files /dev/null and b/1.5/Textures/splatch_3.png differ diff --git a/1.5/Textures/splatch_4.png b/1.5/Textures/splatch_4.png new file mode 100644 index 0000000..7f21495 Binary files /dev/null and b/1.5/Textures/splatch_4.png differ diff --git a/1.5/Textures/splatch_5.png b/1.5/Textures/splatch_5.png new file mode 100644 index 0000000..ee101c1 Binary files /dev/null and b/1.5/Textures/splatch_5.png differ diff --git a/1.5/Textures/splatch_6.png b/1.5/Textures/splatch_6.png new file mode 100644 index 0000000..b9de710 Binary files /dev/null and b/1.5/Textures/splatch_6.png differ diff --git a/1.5/Textures/splatch_7.png b/1.5/Textures/splatch_7.png new file mode 100644 index 0000000..c281066 Binary files /dev/null and b/1.5/Textures/splatch_7.png differ diff --git a/1.5/Textures/splatch_8.png b/1.5/Textures/splatch_8.png new file mode 100644 index 0000000..0fe2c43 Binary files /dev/null and b/1.5/Textures/splatch_8.png differ diff --git a/1.5/Textures/splatch_9.png b/1.5/Textures/splatch_9.png new file mode 100644 index 0000000..0e6a788 Binary files /dev/null and b/1.5/Textures/splatch_9.png differ diff --git a/About/About.xml b/About/About.xml index b3d2aaa..bde4586 100644 --- a/About/About.xml +++ b/About/About.xml @@ -7,6 +7,7 @@
  • 1.3
  • 1.4
  • +
  • 1.5
  • rjw.cum