Separate hats, face hair, glasses from hair (fixes #601)

This commit is contained in:
Cong
2023-07-06 20:19:34 +10:00
parent b54bd4b784
commit 2d05b80ecd
77 changed files with 2146 additions and 1101 deletions

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body", "hair"]
["gun_r", "gun_l", "legs", "head", "body"],
["gun_r", "gun_l", "legs", "head", "body"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 10]],
"idle": [[0, 10]],
"run": [
[0, 11], [0, 10], [0, 9], [0, 10], [0, 11], [0, 10], [0, 9], [0, 10]
]
},
"Head": {
"stand": [[0, 10]],
"idle": [[0, 10]],
@@ -41,9 +34,6 @@
}
},
"Dir": {
"Hair": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],
"Head": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 14], [0, 13], [0, 13], [0, 12], [0, 12], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body", "hair"]
["gun_r", "gun_l", "legs", "head", "body"],
["gun_r", "gun_l", "legs", "head", "body"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 10]],
"idle": [[0, 10]],
"run": [
[0, 11], [0, 10], [0, 9], [0, 10], [0, 11], [0, 10], [0, 9], [0, 10]
]
},
"Head": {
"stand": [[0, 10]],
"idle": [[0, 10]],
@@ -41,9 +34,6 @@
}
},
"Dir": {
"Hair": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],
"Head": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 14], [0, 13], [0, 13], [0, 12], [0, 12], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_r", "gun_l", "legs", "head", "body", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body", "hair"]
["gun_r", "gun_l", "legs", "head", "body"],
["gun_r", "gun_l", "legs", "head", "body"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "head", "body"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 10]],
"idle": [[0, 10]],
"run": [
[0, 11], [0, 10], [0, 9], [0, 10], [0, 11], [0, 10], [0, 9], [0, 10]
]
},
"Head": {
"stand": [[0, 10]],
"idle": [[0, 10]],
@@ -41,9 +34,6 @@
}
},
"Dir": {
"Hair": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],
"Head": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 13], [0, 12], [0, 13], [0, 14], [0, 13], [0, 12], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -35,7 +35,9 @@
},
"Sounds": "alien",
"BloodColor": "00ff00",
"HasHair": false
"HasHair": false,
"HasFacehair": false,
"HasGlasses": false
},
{
"Name": "Mad bug-eye",
@@ -45,7 +47,9 @@
},
"Sounds": "alien",
"BloodColor": "00ff00",
"HasHair": false
"HasHair": false,
"HasFacehair": false,
"HasGlasses": false
},
{
"Name": "Robot",
@@ -55,7 +59,9 @@
},
"Sounds": "alien",
"BloodColor": "0000ff",
"HasHair": false
"HasHair": false,
"HasFacehair": false,
"HasGlasses": false
},
{
"Name": "Lady",
@@ -83,7 +89,9 @@
"Body": "skinny",
"Sounds": "zombie",
"Footsteps": "bones",
"BloodColor": "ffffff"
"BloodColor": "ffffff",
"HasHair": false,
"HasFacehair": false
},
{
"Name": "Big Bones",
@@ -93,8 +101,12 @@
},
"Body": "big_skinny",
"Sounds": "zombie",
"Footsteps": "bones",
"BloodColor": "ffffff",
"HasHair": false
"HasHair": false,
"HasFacehair": false,
"HasHat": false,
"HasGlasses": false
},
{
"Name": "Dog",
@@ -102,7 +114,11 @@
"Type": "Directional",
"Sprites": "chars/heads/dog"
},
"Sounds": "dog"
"Sounds": "dog",
"HasHair": false,
"HasFacehair": false,
"HasHat": false,
"HasGlasses": false
}
]
}

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 13], [0, 12], [0, 13], [0, 14], [0, 13], [0, 12], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 14]],
"idle": [[0, 14]],
"run": [
[0, 15], [0, 14], [0, 13], [0, 14], [0, 15], [0, 14], [0, 13], [0, 14]
]
},
"Head": {
"stand": [[0, 14]],
"idle": [[0, 14]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "gun_l", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 8]],
"idle": [[0, 8]],
"run": [
[0, 8], [0, 7], [0, 7], [0, 8], [0, 8], [0, 9], [0, 9], [0, 8]
]
},
"Head": {
"stand": [[0, 8]],
"idle": [[0, 8]],
@@ -41,9 +34,6 @@
}
},
"Dir": {
"Hair": [
[0, -3], [4, -3], [6, 0], [6, 4], [0, 6], [-6, 4], [-7, 0], [-5, -3]
],
"Head": [
[0, -3], [4, -3], [6, 0], [6, 4], [0, 6], [-6, 4], [-7, 0], [-5, -3]
],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 16]],
"idle": [[0, 16]],
"run": [
[0, 17], [0, 16], [0, 15], [0, 16], [0, 17], [0, 16], [0, 15], [0, 16]
]
},
"Head": {
"stand": [[0, 16]],
"idle": [[0, 16]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 13], [0, 12], [0, 13], [0, 14], [0, 13], [0, 12], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 13]],
"idle": [[0, 13]],
"run": [
[0, 14], [0, 13], [0, 12], [0, 13], [0, 14], [0, 13], [0, 12], [0, 13]
]
},
"Head": {
"stand": [[0, 13]],
"idle": [[0, 13]],

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,23 +1,23 @@
The following are original C-Dogs/Cyberdogs heads, by Ronny Wester CC-BY 3.0 (see graphics/originals.txt)
- beard
The following are extracted from original C-Dogs/Cyberdogs heads, by Ronny Wester CC-BY 3.0 (see graphics/originals.txt)
- beret
- cyber_shades
- cyborg
- dutch
- eye_patch
- flattop
- goggles
- hogan
- mohawk
- ponytail
- professor
- riot_helmet
- shades
- ski_goggles
The following are derived from original C-Dogs/cyberdogs heads. Please still attribute to Ronny Wester using CC-BY 3.0
The following are derived from original C-Dogs/Cyberdogs heads. Please still attribute to Ronny Wester using CC-BY 3.0
- beard
- donut
- mad_doc
- dutch
- handlebar
- rattail
- widows
The following are original and licensed as CC0

View File

@@ -7,10 +7,10 @@
"SkipWeaponMenu": false,
"BuyAndSell": true,
"RandomPickups": false,
"DoorOpenTicks": 0,
"DoorOpenTicks": 70,
"Lives": 0,
"MaxLives": 4,
"PlayerHP": 20,
"PlayerMaxHP": 50,
"Missions": 1
"Missions": 5
}

View File

@@ -1,23 +1,6 @@
{
"Version": 13,
"Version": 14,
"Characters": [{
"Class": "Ogre",
"Skin": "00ff00ff",
"Arms": "404040ff",
"Body": "404040ff",
"Legs": "404040ff",
"Hair": "000000ff",
"Feet": "404040ff",
"speed": 256,
"Gun": "DumbGun",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 0,
"actionDelay": 15
},
{
"Class": "Jones",
"PlayerTemplateName": "Jones",
"Skin": "f0944bff",
@@ -26,6 +9,9 @@
"Legs": "5050a0ff",
"Hair": "000000ff",
"Feet": "5050a0ff",
"Facehair": "000000ff",
"Hat": "000000ff",
"Glasses": "000000ff",
"speed": 256,
"Gun": "Machine gun",
"maxHealth": 40,
@@ -38,13 +24,16 @@
{
"Class": "Jones",
"PlayerTemplateName": "Ice",
"HairType": "shades",
"GlassesType": "shades",
"Skin": "f0944bff",
"Arms": "5050a0ff",
"Body": "5050a0ff",
"Legs": "5050a0ff",
"Hair": "000000ff",
"Feet": "5050a0ff",
"Facehair": "000000ff",
"Hat": "000000ff",
"Glasses": "000000ff",
"speed": 256,
"Gun": "Machine gun",
"maxHealth": 40,
@@ -57,13 +46,16 @@
{
"Class": "Jones",
"PlayerTemplateName": "WarBaby",
"HairType": "beret",
"HatType": "beret",
"Skin": "f0944bff",
"Arms": "5050a0ff",
"Body": "5050a0ff",
"Legs": "5050a0ff",
"Hair": "f30202ff",
"Feet": "5050a0ff",
"Facehair": "f30202ff",
"Hat": "f30202ff",
"Glasses": "f30202ff",
"speed": 256,
"Gun": "Machine gun",
"maxHealth": 40,
@@ -72,5 +64,134 @@
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"HairType": "flattop",
"GlassesType": "cyber_shades",
"Skin": "fc8a20ff",
"Arms": "9c4f4fff",
"Body": "b45f5aff",
"Legs": "cb5c5cff",
"Hair": "0b0101ff",
"Feet": "cd5e5eff",
"Facehair": "ff1616ff",
"Hat": "ff1616ff",
"Glasses": "ff1616ff",
"speed": 256,
"Gun": "DumbGun",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"GlassesType": "cyber_shades",
"Skin": "fc8a20ff",
"Arms": "f70606ff",
"Body": "e9271cff",
"Legs": "ec1010ff",
"Hair": "0b0101ff",
"Feet": "ee0c0cff",
"Facehair": "ff1616ff",
"Hat": "ff1616ff",
"Glasses": "ff1616ff",
"speed": 256,
"Gun": "Lazer",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"GlassesType": "ski_goggles",
"Skin": "fc8a20ff",
"Arms": "a6a4a4ff",
"Body": "a1a0a0ff",
"Legs": "a6a6a6ff",
"Hair": "0b0101ff",
"Feet": "dbd9d9ff",
"Facehair": "ff1616ff",
"Hat": "ff1616ff",
"Glasses": "020000ff",
"speed": 256,
"Gun": "Gun",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"GlassesType": "cyber_shades",
"Skin": "fc8a20ff",
"Arms": "3a3a3aff",
"Body": "3f3f3fff",
"Legs": "464646ff",
"Hair": "0b0101ff",
"Feet": "434343ff",
"Facehair": "ff1616ff",
"Hat": "ff1616ff",
"Glasses": "ff1616ff",
"speed": 256,
"Gun": "Lazer",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"HairType": "donut",
"GlassesType": "goggles",
"Skin": "fc8a20ff",
"Arms": "9c4f4fff",
"Body": "b45f5aff",
"Legs": "cb5c5cff",
"Hair": "0b0101ff",
"Feet": "cd5e5eff",
"Facehair": "ff1616ff",
"Hat": "ff1616ff",
"Glasses": "fcfcfcff",
"speed": 256,
"Gun": "DumbGun",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
},
{
"Class": "Cyborg",
"HatType": "beret",
"GlassesType": "cyber_shades",
"Skin": "fc8a20ff",
"Arms": "4a4a4aff",
"Body": "565555ff",
"Legs": "5d5d5dff",
"Hair": "0b0101ff",
"Feet": "545454ff",
"Facehair": "ff1616ff",
"Hat": "7b7b7bff",
"Glasses": "ff1616ff",
"speed": 256,
"Gun": "TurboLazer",
"maxHealth": 40,
"flags": 1024,
"probabilityToMove": 50,
"probabilityToTrack": 25,
"probabilityToShoot": 2,
"actionDelay": 15
}]
}

View File

@@ -15,8 +15,8 @@
"pci_card",
"paper",
"teddy"],
"Count": 8,
"Required": 0,
"Count": 12,
"Required": 6,
"Flags": 0
}],
"Enemies": [0],
@@ -84,8 +84,540 @@
"Room": {
"Name": "tile",
"Type": "Floor",
"Style": "recessed",
"Mask": "707070ff",
"Style": "wood",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": true,
"DamageBullet": ""
},
"Door": {
"Name": "door",
"Type": "Door",
"Style": "office",
"Mask": "ffffffff",
"MaskAlt": "ffffffff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": true,
"DamageBullet": ""
}
},
"Walls": 140,
"WallLength": 20,
"CorridorWidth": 2,
"Rooms": {
"Count": 30,
"Min": 7,
"Max": 10,
"Edge": false,
"Overlap": false,
"Walls": 0,
"WallLength": 1,
"WallPad": 1
},
"Squares": 1,
"ExitEnabled": true,
"Doors": {
"Enabled": false,
"Min": 2,
"Max": 2,
"RandomPos": false
},
"Pillars": {
"Count": 0,
"Min": 2,
"Max": 3
}
},
{
"Title": "Mission 2",
"Description": "",
"Type": "Classic",
"Width": 100,
"Height": 100,
"ExitStyle": "hazard",
"KeyStyle": "office",
"Objectives": [{
"Description": "",
"Type": "Collect",
"Pickups": ["folder",
"disk1",
"pci_card",
"paper",
"teddy"],
"Count": 16,
"Required": 8,
"Flags": 0
}],
"Enemies": [0],
"SpecialChars": [],
"MapObjectDensities": [{
"MapObject": "crate",
"Density": 45
},
{
"MapObject": "box",
"Density": 45
},
{
"MapObject": "fan",
"Density": 20
},
{
"MapObject": "barrel_blue",
"Density": 30
},
{
"MapObject": "box3_gray",
"Density": 30
}],
"EnemyDensity": 13,
"Weapons": ["Barehanded",
"Chainsaw",
"2xChainsaw",
"3xChainsaw",
"4xChainsaw",
"5xChainsaw",
"MiniGun",
"Launcher",
"Flamer",
"Powergun",
"Blaster",
"MegaGun"],
"WeaponPersist": false,
"SkipDebrief": false,
"TileClasses": {
"Wall": {
"Name": "wall",
"Type": "Wall",
"Style": "brick",
"Mask": "34345cff",
"MaskAlt": "008400ff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": false,
"DamageBullet": ""
},
"Floor": {
"Name": "tile",
"Type": "Floor",
"Style": "smallsquare2",
"Mask": "282848ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": false,
"DamageBullet": ""
},
"Room": {
"Name": "tile",
"Type": "Floor",
"Style": "smallsquare2",
"Mask": "282848ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": true,
"DamageBullet": ""
},
"Door": {
"Name": "door",
"Type": "Door",
"Style": "office",
"Mask": "ffffffff",
"MaskAlt": "ffffffff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": true,
"DamageBullet": ""
}
},
"Walls": 140,
"WallLength": 20,
"CorridorWidth": 2,
"Rooms": {
"Count": 30,
"Min": 7,
"Max": 10,
"Edge": false,
"Overlap": false,
"Walls": 0,
"WallLength": 1,
"WallPad": 1
},
"Squares": 1,
"ExitEnabled": true,
"Doors": {
"Enabled": false,
"Min": 2,
"Max": 2,
"RandomPos": false
},
"Pillars": {
"Count": 0,
"Min": 2,
"Max": 3
}
},
{
"Title": "Mission 3",
"Description": "",
"Type": "Classic",
"Width": 100,
"Height": 100,
"ExitStyle": "hazard",
"KeyStyle": "office",
"Objectives": [{
"Description": "",
"Type": "Collect",
"Pickups": ["folder",
"disk1",
"pci_card",
"paper",
"teddy"],
"Count": 20,
"Required": 10,
"Flags": 0
}],
"Enemies": [0],
"SpecialChars": [],
"MapObjectDensities": [{
"MapObject": "crate",
"Density": 45
},
{
"MapObject": "box",
"Density": 45
},
{
"MapObject": "fan",
"Density": 20
},
{
"MapObject": "barrel_blue",
"Density": 30
},
{
"MapObject": "box3_gray",
"Density": 30
}],
"EnemyDensity": 13,
"Weapons": ["Barehanded",
"Chainsaw",
"2xChainsaw",
"3xChainsaw",
"4xChainsaw",
"5xChainsaw",
"MiniGun",
"Launcher",
"Flamer",
"Powergun",
"Blaster",
"MegaGun"],
"WeaponPersist": false,
"SkipDebrief": false,
"TileClasses": {
"Wall": {
"Name": "wall",
"Type": "Wall",
"Style": "brick",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": false,
"DamageBullet": ""
},
"Floor": {
"Name": "tile",
"Type": "Floor",
"Style": "dirt",
"Mask": "584418ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": false,
"DamageBullet": ""
},
"Room": {
"Name": "tile",
"Type": "Floor",
"Style": "dirt",
"Mask": "584418ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": true,
"DamageBullet": ""
},
"Door": {
"Name": "door",
"Type": "Door",
"Style": "office",
"Mask": "ffffffff",
"MaskAlt": "ffffffff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": true,
"DamageBullet": ""
}
},
"Walls": 140,
"WallLength": 20,
"CorridorWidth": 2,
"Rooms": {
"Count": 30,
"Min": 7,
"Max": 10,
"Edge": false,
"Overlap": false,
"Walls": 0,
"WallLength": 1,
"WallPad": 1
},
"Squares": 1,
"ExitEnabled": true,
"Doors": {
"Enabled": false,
"Min": 2,
"Max": 2,
"RandomPos": false
},
"Pillars": {
"Count": 0,
"Min": 2,
"Max": 3
}
},
{
"Title": "Mission 4",
"Description": "",
"Type": "Classic",
"Width": 100,
"Height": 100,
"ExitStyle": "hazard",
"KeyStyle": "office",
"Objectives": [{
"Description": "",
"Type": "Collect",
"Pickups": ["folder",
"disk1",
"pci_card",
"paper",
"teddy"],
"Count": 24,
"Required": 12,
"Flags": 0
}],
"Enemies": [0],
"SpecialChars": [],
"MapObjectDensities": [{
"MapObject": "crate",
"Density": 45
},
{
"MapObject": "box",
"Density": 45
},
{
"MapObject": "fan",
"Density": 20
},
{
"MapObject": "barrel_blue",
"Density": 30
},
{
"MapObject": "box3_gray",
"Density": 30
}],
"EnemyDensity": 13,
"Weapons": ["Barehanded",
"Chainsaw",
"2xChainsaw",
"3xChainsaw",
"4xChainsaw",
"5xChainsaw",
"MiniGun",
"Launcher",
"Flamer",
"Powergun",
"Blaster",
"MegaGun"],
"WeaponPersist": false,
"SkipDebrief": false,
"TileClasses": {
"Wall": {
"Name": "wall",
"Type": "Wall",
"Style": "brick",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": false,
"DamageBullet": ""
},
"Floor": {
"Name": "tile",
"Type": "Floor",
"Style": "wood",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": false,
"DamageBullet": ""
},
"Room": {
"Name": "tile",
"Type": "Floor",
"Style": "wood",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": true,
"DamageBullet": ""
},
"Door": {
"Name": "door",
"Type": "Door",
"Style": "office",
"Mask": "ffffffff",
"MaskAlt": "ffffffff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": true,
"DamageBullet": ""
}
},
"Walls": 140,
"WallLength": 20,
"CorridorWidth": 2,
"Rooms": {
"Count": 30,
"Min": 7,
"Max": 10,
"Edge": false,
"Overlap": false,
"Walls": 0,
"WallLength": 1,
"WallPad": 1
},
"Squares": 1,
"ExitEnabled": true,
"Doors": {
"Enabled": false,
"Min": 2,
"Max": 2,
"RandomPos": false
},
"Pillars": {
"Count": 0,
"Min": 2,
"Max": 3
}
},
{
"Title": "Mission 5",
"Description": "",
"Type": "Classic",
"Width": 100,
"Height": 100,
"ExitStyle": "hazard",
"KeyStyle": "office",
"Objectives": [{
"Description": "",
"Type": "Kill",
"Index": 0,
"Count": 90,
"Required": 70,
"Flags": 0
}],
"Enemies": [0],
"SpecialChars": [],
"MapObjectDensities": [{
"MapObject": "crate",
"Density": 45
},
{
"MapObject": "box",
"Density": 45
},
{
"MapObject": "fan",
"Density": 20
},
{
"MapObject": "barrel_blue",
"Density": 30
},
{
"MapObject": "box3_gray",
"Density": 30
}],
"EnemyDensity": 13,
"Weapons": ["Barehanded",
"Chainsaw",
"2xChainsaw",
"3xChainsaw",
"4xChainsaw",
"5xChainsaw",
"MiniGun",
"Launcher",
"Flamer",
"Powergun",
"Blaster",
"MegaGun"],
"WeaponPersist": true,
"SkipDebrief": false,
"TileClasses": {
"Wall": {
"Name": "wall",
"Type": "Wall",
"Style": "brick",
"Mask": "303030ff",
"MaskAlt": "008400ff",
"CanWalk": false,
"IsOpaque": true,
"Shootable": true,
"IsRoom": false,
"DamageBullet": ""
},
"Floor": {
"Name": "tile",
"Type": "Floor",
"Style": "dirt",
"Mask": "584418ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,
"Shootable": false,
"IsRoom": false,
"DamageBullet": ""
},
"Room": {
"Name": "tile",
"Type": "Floor",
"Style": "dirt",
"Mask": "584418ff",
"MaskAlt": "008400ff",
"CanWalk": true,
"IsOpaque": false,

View File

@@ -9,8 +9,7 @@
},
"Body": "demon",
"Sounds": "ogre",
"BloodColor": "ff0000",
"HasHair": true
"BloodColor": "ff0000"
}
]
}

View File

@@ -1,24 +1,17 @@
{
"Version": 2,
"Order": [
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_r", "gun_l", "legs", "body", "head", "hair"],
["gun_l", "legs", "body", "head", "hair", "gun_r"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "body", "head", "hair", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "hair", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head", "hair"]
["gun_r", "gun_l", "legs", "body", "head"],
["gun_r", "gun_l", "legs", "body", "head"],
["gun_l", "legs", "body", "head", "gun_r"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "body", "head", "gun_r", "gun_l"],
["legs", "gun_r", "body", "head", "gun_l"],
["gun_r", "gun_l", "legs", "body", "head"]
],
"Offsets": {
"Frame": {
"Hair": {
"stand": [[0, 10]],
"idle": [[0, 10]],
"run": [
[0, 11], [0, 10], [0, 9], [0, 10], [0, 11], [0, 10], [0, 9], [0, 10]
]
},
"Head": {
"stand": [[0, 10]],
"idle": [[0, 10]],
@@ -41,9 +34,6 @@
}
},
"Dir": {
"Hair": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],
"Head": [
[0, -2], [2, -1], [4, 0], [2, 1], [0, 2], [-2, 1], [-4, 0], [-2, -1]
],

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2020 Cong Xu
Copyright (c) 2013-2020, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -54,6 +54,12 @@ color_t *CharColorGetByType(CharColors *c, const CharColorType t)
return &c->Hair;
case CHAR_COLOR_FEET:
return &c->Feet;
case CHAR_COLOR_FACEHAIR:
return &c->Facehair;
case CHAR_COLOR_HAT:
return &c->Hat;
case CHAR_COLOR_GLASSES:
return &c->Glasses;
default:
CASSERT(false, "Unexpected colour");
return &c->Skin;
@@ -75,7 +81,7 @@ color_t *CharColorGetByType(CharColors *c, const CharColorType t)
uint8_t CharColorTypeAlpha(const CharColorType t)
{
static uint8_t alphas[] = {254, 253, 252, 251, 250, 249};
static uint8_t alphas[] = {254, 253, 252, 251, 250, 249, 248, 247, 246};
if (t < CHAR_COLOR_COUNT)
{
return alphas[t];
@@ -83,7 +89,7 @@ uint8_t CharColorTypeAlpha(const CharColorType t)
return 255;
}
#define CHAR_COLOR_THRESHOLD 5
CharColorType CharColorTypeFromColor(const color_t c)
CharColorType CharColorTypeFromColor(const color_t c, const CharColorType headPartColor)
{
if (abs((int)c.r - c.g) < CHAR_COLOR_THRESHOLD &&
abs((int)c.g - c.b) < CHAR_COLOR_THRESHOLD &&
@@ -99,8 +105,8 @@ CharColorType CharColorTypeFromColor(const color_t c)
}
else if ((c.r < 5 && c.b < 5) || (abs((int)c.r - c.b) < 5 && c.g > 250))
{
// Hair (G)
return CHAR_COLOR_HAIR;
// Head parts (G)
return headPartColor;
}
else if ((c.r < 5 && c.g < 5) || (abs((int)c.r - c.g) < 5 && c.b > 250))
{
@@ -127,7 +133,7 @@ CharColorType CharColorTypeFromColor(const color_t c)
}
CharColors CharColorsFromOneColor(const color_t color)
{
CharColors c = {color, color, color, color, color, color};
CharColors c = {color, color, color, color, color, color, color, color, color};
return c;
}
color_t CharColorsGetChannelMask(const CharColors *c, const uint8_t alpha)
@@ -148,6 +154,12 @@ color_t CharColorsGetChannelMask(const CharColors *c, const uint8_t alpha)
return c->Hair;
case 249:
return c->Feet;
case 248:
return c->Facehair;
case 247:
return c->Hat;
case 246:
return c->Glasses;
default:
return colorWhite;
}
@@ -156,16 +168,20 @@ void CharColorsGetMaskedName(char *buf, const char *base, const CharColors *c)
{
char bufSkin[COLOR_STR_BUF], bufArms[COLOR_STR_BUF],
bufBody[COLOR_STR_BUF], bufLegs[COLOR_STR_BUF], bufHair[COLOR_STR_BUF],
bufFeet[COLOR_STR_BUF];
bufFeet[COLOR_STR_BUF], bufFacehair[COLOR_STR_BUF], bufHat[COLOR_STR_BUF],
bufGlasses[COLOR_STR_BUF];
ColorStr(bufSkin, c->Skin);
ColorStr(bufArms, c->Arms);
ColorStr(bufBody, c->Body);
ColorStr(bufLegs, c->Legs);
ColorStr(bufHair, c->Hair);
ColorStr(bufFeet, c->Feet);
ColorStr(bufFacehair, c->Facehair);
ColorStr(bufHat, c->Hat);
ColorStr(bufGlasses, c->Glasses);
sprintf(
buf, "%s/%s/%s/%s/%s/%s/%s", base, bufSkin, bufArms, bufBody, bufLegs,
bufHair, bufFeet);
buf, "%s/%s/%s/%s/%s/%s/%s/%s/%s/%s", base, bufSkin, bufArms, bufBody, bufLegs,
bufHair, bufFeet, bufFacehair, bufHat, bufGlasses);
}
void BlitClearBuf(GraphicsDevice *g)

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2014, 2016-2020 Cong Xu
Copyright (c) 2013-2014, 2016-2020, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,9 @@ typedef struct
color_t Legs;
color_t Hair;
color_t Feet;
color_t Facehair;
color_t Hat;
color_t Glasses;
} CharColors;
typedef enum
{
@@ -50,6 +53,9 @@ typedef enum
CHAR_COLOR_LEGS,
CHAR_COLOR_HAIR,
CHAR_COLOR_FEET,
CHAR_COLOR_FACEHAIR,
CHAR_COLOR_HAT,
CHAR_COLOR_GLASSES,
CHAR_COLOR_COUNT
} CharColorType;
color_t *CharColorGetByType(CharColors *c, const CharColorType t);
@@ -59,7 +65,7 @@ void BlitFillBuf(GraphicsDevice *g, const color_t c);
void BlitUpdateFromBuf(GraphicsDevice *g, SDL_Texture *t);
uint8_t CharColorTypeAlpha(const CharColorType t);
CharColorType CharColorTypeFromColor(const color_t c);
CharColorType CharColorTypeFromColor(const color_t c, const CharColorType headPartColor);
CharColors CharColorsFromOneColor(const color_t color);
color_t CharColorsGetChannelMask(const CharColors *c, const uint8_t alpha);
void CharColorsGetMaskedName(char *buf, const char *base, const CharColors *c);

View File

@@ -35,7 +35,7 @@
#include "json_utils.h"
#include "player_template.h"
#define CHARACTER_VERSION 13
#define CHARACTER_VERSION 14
static void CharacterInit(Character *c)
{
@@ -44,7 +44,10 @@ static void CharacterInit(Character *c)
}
static void CharacterTerminate(Character *c)
{
CFREE(c->Hair);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CFREE(c->HeadParts[hp]);
}
CFREE(c->bot);
}
@@ -80,10 +83,12 @@ void CharacterStoreCopy(
const CharBot *cb = c->bot;
CMALLOC(c->bot, sizeof *c->bot);
memcpy(c->bot, cb, sizeof *cb);
const char *hair = c->Hair;
if (hair != NULL)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CSTRDUP(c->Hair, hair);
if (c->HeadParts[hp] != NULL)
{
CSTRDUP(c->HeadParts[hp], c->HeadParts[hp]);
}
}
if (c->PlayerTemplateName != NULL)
{
@@ -130,7 +135,7 @@ void CharacterLoadJSON(
tmp = GetString(child, "Class");
}
char *face = NULL;
CharacterOldFaceToHair(tmp, &face, &ch->Hair);
CharacterOldFaceToHeadParts(tmp, &face, ch->HeadParts);
CFREE(tmp);
ch->Class = StrCharacterClass(face);
CFREE(face);
@@ -141,8 +146,17 @@ void CharacterLoadJSON(
ch->Class = StrCharacterClass(tmp);
CFREE(tmp);
tmp = NULL;
LoadStr(&ch->Hair, child, "HairType");
CFREE(tmp);
LoadStr(&ch->HeadParts[HEAD_PART_HAIR], child, "HairType");
if (version < 14)
{
CharacterOldHairToHeadParts(ch->HeadParts);
}
else
{
LoadStr(&ch->HeadParts[HEAD_PART_FACEHAIR], child, "FacehairType");
LoadStr(&ch->HeadParts[HEAD_PART_HAT], child, "HatType");
LoadStr(&ch->HeadParts[HEAD_PART_GLASSES], child, "GlassesType");
}
}
CASSERT(ch->Class != NULL, "Cannot load character class");
@@ -167,14 +181,27 @@ void CharacterLoadJSON(
LoadColor(&ch->Colors.Hair, child, "Hair");
}
ch->Colors.Feet = ch->Colors.Legs;
if (version >= 13)
{
LoadColor(&ch->Colors.Feet, child, "Feet");
}
if (version < 12)
if (version < 13)
{
ConvertHairColors(ch, ch->Class->Name);
}
else
{
LoadColor(&ch->Colors.Feet, child, "Feet");
}
if (version < 14)
{
ch->Colors.Facehair = ch->Colors.Hair;
ch->Colors.Hat = ch->Colors.Hair;
ch->Colors.Glasses = ch->Colors.Hair;
}
else
{
LoadColor(&ch->Colors.Facehair, child, "Facehair");
LoadColor(&ch->Colors.Hat, child, "Hat");
LoadColor(&ch->Colors.Glasses, child, "Glasses");
}
LoadStr(&ch->PlayerTemplateName, child, "PlayerTemplateName");
LoadFullInt(&ch->speed, child, "speed");
tmp = GetString(child, "Gun");
@@ -221,9 +248,21 @@ bool CharacterSave(CharacterStore *s, const char *path)
{
AddStringPair(node, "PlayerTemplateName", c->PlayerTemplateName);
}
if (c->Hair)
if (c->HeadParts[HEAD_PART_HAIR])
{
AddStringPair(node, "HairType", c->Hair);
AddStringPair(node, "HairType", c->HeadParts[HEAD_PART_HAIR]);
}
if (c->HeadParts[HEAD_PART_FACEHAIR])
{
AddStringPair(node, "FacehairType", c->HeadParts[HEAD_PART_FACEHAIR]);
}
if (c->HeadParts[HEAD_PART_HAT])
{
AddStringPair(node, "HatType", c->HeadParts[HEAD_PART_HAT]);
}
if (c->HeadParts[HEAD_PART_GLASSES])
{
AddStringPair(node, "GlassesType", c->HeadParts[HEAD_PART_GLASSES]);
}
AddColorPair(node, "Skin", c->Colors.Skin);
AddColorPair(node, "Arms", c->Colors.Arms);
@@ -231,6 +270,9 @@ bool CharacterSave(CharacterStore *s, const char *path)
AddColorPair(node, "Legs", c->Colors.Legs);
AddColorPair(node, "Hair", c->Colors.Hair);
AddColorPair(node, "Feet", c->Colors.Feet);
AddColorPair(node, "Facehair", c->Colors.Facehair);
AddColorPair(node, "Hat", c->Colors.Hat);
AddColorPair(node, "Glasses", c->Colors.Glasses);
AddIntPair(node, "speed", (int)(c->speed * 256));
json_insert_pair_into_object(node, "Gun", json_new_string(c->Gun->name));
AddIntPair(node, "maxHealth", c->maxHealth);
@@ -332,6 +374,16 @@ bool CharacterIsPrisoner(const CharacterStore *store, const Character *c)
return false;
}
void CharacterSetHeadPart(Character *c, const HeadPart hp, const char *name)
{
CFREE(c->HeadParts[hp]);
c->HeadParts[hp] = NULL;
if (name)
{
CSTRDUP(c->HeadParts[hp], name);
}
}
static color_t RandomColor(void);
void CharacterShuffleAppearance(Character *c)
{
@@ -349,16 +401,26 @@ void CharacterShuffleAppearance(Character *c)
&gCharacterClasses.CustomClasses,
charClass - gCharacterClasses.Classes.size);
}
CFREE(c->Hair);
const char *hairStyleName = *(char **)CArrayGet(
&gPicManager.hairstyleNames, rand() % gPicManager.hairstyleNames.size);
CSTRDUP(c->Hair, hairStyleName);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
if (RAND_BOOL())
{
const CArray *hpNames = &gPicManager.headPartNames[hp];
const char *name = *(char **)CArrayGet(hpNames, rand() % hpNames->size);
CharacterSetHeadPart(c, hp, name);
}
}
c->Colors.Skin = RandomColor();
c->Colors.Arms = RandomColor();
c->Colors.Body = RandomColor();
c->Colors.Legs = RandomColor();
c->Colors.Hair = RandomColor();
c->Colors.Feet = RandomColor();
c->Colors.Facehair = c->Colors.Hair;
c->Colors.Hat = RandomColor();
c->Colors.Glasses = RandomColor();
}
static color_t RandomColor(void)
{

View File

@@ -46,7 +46,7 @@ typedef struct
{
const CharacterClass *Class;
char *PlayerTemplateName;
char *Hair;
char *HeadParts[HEAD_PART_COUNT];
float speed;
const WeaponClass *Gun;
int maxHealth;
@@ -89,4 +89,5 @@ int CharacterStoreGetRandomSpecialId(const CharacterStore *store);
bool CharacterIsPrisoner(const CharacterStore *store, const Character *c);
void CharacterSetHeadPart(Character *c, const HeadPart hp, const char *name);
void CharacterShuffleAppearance(Character *c);

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2016-2017, 2019-2021 Cong Xu
Copyright (c) 2016-2017, 2019-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -62,103 +62,107 @@ const char *IntCharacterFace(const int face)
{
return characterNames[face];
}
void CharacterOldFaceToHair(const char *face, char **newFace, char **hair)
void CharacterOldFaceToHeadParts(const char *face, char **newFace, char *headParts[HEAD_PART_COUNT])
{
// Convert old faces to face + hair
if (strcmp(face, "Bob") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "beard");
CSTRDUP(headParts[HEAD_PART_HAIR], "flattop");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "beard");
}
else if (strcmp(face, "Cyber Jones") == 0)
{
CSTRDUP(*newFace, "Cyborg");
CSTRDUP(*hair, "cyber_shades");
CSTRDUP(headParts[HEAD_PART_GLASSES], "cyber_shades");
}
else if (strcmp(face, "Cyber Smith") == 0)
{
CSTRDUP(*newFace, "Cyborg");
CSTRDUP(*hair, "flattop");
CSTRDUP(headParts[HEAD_PART_HAIR], "flattop");
}
else if (strcmp(face, "Cyber WarBaby") == 0)
{
CSTRDUP(*newFace, "Cyborg");
CSTRDUP(*hair, "beret");
CSTRDUP(headParts[HEAD_PART_HAT], "beret");
}
else if (strcmp(face, "Cyborg") == 0)
{
CSTRDUP(*newFace, "Cyborg");
CSTRDUP(*hair, "cyborg");
CSTRDUP(headParts[HEAD_PART_GLASSES], "cyborg");
}
else if (strcmp(face, "Dragon") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "hogan");
CSTRDUP(headParts[HEAD_PART_HAIR], "rattail");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "handlebar");
}
else if (strcmp(face, "Evil Ogre") == 0)
{
CSTRDUP(*newFace, "Ogre");
CSTRDUP(*hair, "horns");
CSTRDUP(headParts[HEAD_PART_HAT], "horns");
}
else if (strcmp(face, "Freeze") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "ski_goggles");
CSTRDUP(headParts[HEAD_PART_GLASSES], "ski_goggles");
}
else if (strcmp(face, "Goggles") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "goggles");
CSTRDUP(headParts[HEAD_PART_GLASSES], "goggles");
}
else if (strcmp(face, "Grunt") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "riot_helmet");
CSTRDUP(headParts[HEAD_PART_HAT], "riot_helmet");
}
else if (strcmp(face, "Ice") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "shades");
CSTRDUP(headParts[HEAD_PART_GLASSES], "shades");
}
else if (strcmp(face, "Lady") == 0)
{
CSTRDUP(*newFace, "Lady");
CSTRDUP(*hair, "ponytail");
CSTRDUP(headParts[HEAD_PART_HAIR], "ponytail");
}
else if (strcmp(face, "Ogre Boss") == 0)
{
CSTRDUP(*newFace, "Ogre");
CSTRDUP(*hair, "mohawk");
CSTRDUP(headParts[HEAD_PART_HAIR], "mohawk");
}
else if (strcmp(face, "Professor") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "professor");
CSTRDUP(headParts[HEAD_PART_HAIR], "donut");
CSTRDUP(headParts[HEAD_PART_GLASSES], "goggles");
}
else if (strcmp(face, "Smith") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "flattop");
CSTRDUP(headParts[HEAD_PART_HAIR], "flattop");
}
else if (strcmp(face, "Snake") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "eye_patch");
CSTRDUP(headParts[HEAD_PART_GLASSES], "eye_patch");
}
else if (strcmp(face, "Sweeper") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "helmet");
CSTRDUP(headParts[HEAD_PART_HAT], "helmet");
}
else if (strcmp(face, "WarBaby") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "beret");
CSTRDUP(headParts[HEAD_PART_HAT], "beret");
}
else if (strcmp(face, "Wolf") == 0)
{
CSTRDUP(*newFace, "Jones");
CSTRDUP(*hair, "dutch");
CSTRDUP(headParts[HEAD_PART_HAIR], "widows");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "dutch");
}
else
{
@@ -166,6 +170,112 @@ void CharacterOldFaceToHair(const char *face, char **newFace, char **hair)
}
}
void CharacterOldHairToHeadParts(char *headParts[HEAD_PART_COUNT])
{
const char *hair = headParts[HEAD_PART_HAIR];
if (hair == NULL)
{
return;
}
if (strcmp(hair, "beard") == 0)
{
CSTRDUP(headParts[HEAD_PART_HAIR], "flattop");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "beard");
}
else if (strcmp(hair, "beret") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "beret");
}
else if (strcmp(hair, "combat_helmet") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "combat_helmet");
}
else if (strcmp(hair, "cyber_shades") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_GLASSES], "cyber_shades");
}
else if (strcmp(hair, "cyborg") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_GLASSES], "cyborg");
}
else if (strcmp(hair, "dutch") == 0)
{
CSTRDUP(headParts[HEAD_PART_HAIR], "widows");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "dutch");
}
else if (strcmp(hair, "eye_patch") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_GLASSES], "eye_patch");
}
else if (strcmp(hair, "goggles") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_GLASSES], "goggles");
}
else if (strcmp(hair, "hazmat") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "hazmat");
}
else if (strcmp(hair, "helmet") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "helmet");
}
else if (strcmp(hair, "hogan") == 0)
{
CSTRDUP(headParts[HEAD_PART_HAIR], "rattail");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "handlebar");
}
else if (strcmp(hair, "horns") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "horns");
}
else if (strcmp(hair, "mad_doc") == 0)
{
CSTRDUP(headParts[HEAD_PART_HAIR], "donut");
CSTRDUP(headParts[HEAD_PART_FACEHAIR], "beard");
}
else if (strcmp(hair, "peak_cap") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "peak_cap");
}
else if (strcmp(hair, "professor") == 0)
{
CSTRDUP(headParts[HEAD_PART_HAIR], "donut");
CSTRDUP(headParts[HEAD_PART_GLASSES], "goggles");
}
else if (strcmp(hair, "riot_helmet") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_HAT], "riot_helmet");
}
else if (strcmp(hair, "ski_goggles") == 0)
{
CFREE(headParts[HEAD_PART_HAIR]);
headParts[HEAD_PART_HAIR] = NULL;
CSTRDUP(headParts[HEAD_PART_GLASSES], "ski_goggles");
}
}
const NamedSprites *CharacterClassGetDeathSprites(const CharacterClass *c, const PicManager *pm)
{
char buf[256];
@@ -293,8 +403,17 @@ static void LoadCharacterClass(CharacterClass *c, json_t *node)
c->BloodColor = colorRed;
LoadColor(&c->BloodColor, node, "BloodColor");
c->HasHair = true;
LoadBool(&c->HasHair, node, "HasHair");
// By default player classes allow cranial accessories
// But some types can't/shouldn't have stuff like hair
// For example the alien
c->HasHeadParts[HEAD_PART_HAIR] = true;
LoadBool(&c->HasHeadParts[HEAD_PART_HAIR], node, "HasHair");
c->HasHeadParts[HEAD_PART_FACEHAIR] = true;
LoadBool(&c->HasHeadParts[HEAD_PART_FACEHAIR], node, "HasFacehair");
c->HasHeadParts[HEAD_PART_HAT] = true;
LoadBool(&c->HasHeadParts[HEAD_PART_HAT], node, "HasHat");
c->HasHeadParts[HEAD_PART_GLASSES] = true;
LoadBool(&c->HasHeadParts[HEAD_PART_GLASSES], node, "HasGlasses");
LoadStr(&c->Corpse, node, "Corpse");
}

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2016-2021 Cong Xu
Copyright (c) 2016-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@ typedef struct
int FootstepsDistancePlus;
color_t BloodColor;
char *Corpse;
bool HasHair;
bool HasHeadParts[HEAD_PART_COUNT];
} CharacterClass;
typedef struct
{
@@ -62,7 +62,8 @@ extern CharacterClasses gCharacterClasses;
const CharacterClass *StrCharacterClass(const char *s);
// Legacy character class from "face" index
const char *IntCharacterFace(const int face);
void CharacterOldFaceToHair(const char *face, char **newFace, char **hair);
void CharacterOldFaceToHeadParts(const char *face, char **newFace, char *headParts[HEAD_PART_COUNT]);
void CharacterOldHairToHeadParts(char *headParts[HEAD_PART_COUNT]);
const NamedSprites *CharacterClassGetDeathSprites(const CharacterClass *c, const PicManager *pm);
const CharacterClass *IndexCharacterClass(const int i);
int CharacterClassIndex(const CharacterClass *c);

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2017, 2019-2020 Cong Xu
Copyright (c) 2017, 2019-2020, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -130,16 +130,29 @@ static CharSprites *CharSpritesLoadJSON(const char *name, const char *path)
for (direction_e d = DIRECTION_UP; d < DIRECTION_COUNT; d++)
{
const yajl_array orderDir = YAJL_GET_ARRAY(order->values[d]);
int i = 0;
for (BodyPart bp = BODY_PART_HEAD; bp < BODY_PART_COUNT; bp++)
{
c->Order[d][bp] =
StrBodyPart(YAJL_GET_STRING(orderDir->values[bp]));
StrBodyPart(YAJL_GET_STRING(orderDir->values[i]));
i++;
// Always draw head-parts in the following order:
// head, facehair, glasses, hair, hat
// Use the order for "head" and ignore the rest
if (c->Order[d][bp] == BODY_PART_HEAD)
{
c->Order[d][++bp] = BODY_PART_FACEHAIR;
c->Order[d][++bp] = BODY_PART_GLASSES;
c->Order[d][++bp] = BODY_PART_HAIR;
c->Order[d][++bp] = BODY_PART_HAT;
}
}
}
c->Offsets.Frame[BODY_PART_HEAD] =
LoadFrameOffsets(node, "Offsets/Frame/Head");
c->Offsets.Frame[BODY_PART_HAIR] =
LoadFrameOffsets(node, "Offsets/Frame/Hair");
// Use same offsets for head parts
for (BodyPart bp = BODY_PART_HEAD; bp <= BODY_PART_GLASSES; bp++)
{
c->Offsets.Frame[bp] = LoadFrameOffsets(node, "Offsets/Frame/Head");
}
c->Offsets.Frame[BODY_PART_BODY] =
LoadFrameOffsets(node, "Offsets/Frame/Body");
c->Offsets.Frame[BODY_PART_LEGS] =
@@ -149,7 +162,11 @@ static CharSprites *CharSpritesLoadJSON(const char *name, const char *path)
c->Offsets.Frame[BODY_PART_GUN_L] =
LoadFrameOffsets(node, "Offsets/Frame/Gun");
LoadDirOffsets(c->Offsets.Dir[BODY_PART_HEAD], node, "Offsets/Dir/Head");
LoadDirOffsets(c->Offsets.Dir[BODY_PART_HAIR], node, "Offsets/Dir/Hair");
// Use same offsets for head parts
for (BodyPart bp = BODY_PART_HEAD + 1; bp <= BODY_PART_GLASSES; bp++)
{
memcpy(&c->Offsets.Dir[bp], &c->Offsets.Dir[BODY_PART_HEAD], sizeof c->Offsets.Dir[bp]);
}
LoadDirOffsets(c->Offsets.Dir[BODY_PART_BODY], node, "Offsets/Dir/Body");
LoadDirOffsets(c->Offsets.Dir[BODY_PART_LEGS], node, "Offsets/Dir/Legs");
LoadDirOffsets(c->Offsets.Dir[BODY_PART_GUN_R], node, "Offsets/Dir/Gun");
@@ -206,12 +223,22 @@ void CharSpriteClassesClear(map_t classes)
{
hashmap_destroy(classes, CharSpritesDestroy);
}
static void OffsetFrameDestroy(any_t data);
static void CharSpritesDestroy(any_t data)
{
CharSprites *c = data;
CFREE(c->Name);
for (int i = 0; i < BODY_PART_COUNT + MAX_BARRELS - 1; i++)
{
hashmap_destroy(c->Offsets.Frame[i], OffsetFrameDestroy);
}
CFREE(c);
}
static void OffsetFrameDestroy(any_t data)
{
CArray *offsets = data;
CArrayTerminate(offsets);
}
void CharSpriteClassesTerminate(CharSpriteClasses *c)
{
CharSpriteClassesClear(c->classes);

View File

@@ -22,7 +22,7 @@
This file incorporates work covered by the following copyright and
permission notice:
Copyright (c) 2013-2021 Cong Xu
Copyright (c) 2013-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -191,8 +191,7 @@ static void UpdatePilotHeadPic(
return;
}
// If this is a vehicle, take the head/hair pic from the pilot
pics->Head = NULL;
pics->Hair = NULL;
memset(&pics->HeadParts, 0, sizeof pics->HeadParts);
const TActor *pilot = ActorGetByUID(a->pilotUID);
if (pilot == NULL)
{
@@ -201,9 +200,13 @@ static void UpdatePilotHeadPic(
const Character *c = ActorGetCharacter(pilot);
const bool grimace = ActorIsGrimacing(a);
pics->Head = GetHeadPic(c->Class, dir, grimace, &c->Colors);
if (c->Class->HasHair)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
pics->Hair = GetHairPic(c->Hair, dir, grimace, &c->Colors);
if (c->Class->HasHeadParts[hp])
{
pics->HeadParts[hp] = GetHeadPartPic(c->HeadParts[hp], hp, dir, grimace, &c->Colors);
}
}
}
ActorPics GetCharacterPics(
@@ -312,13 +315,17 @@ static ActorPics GetUnorderedPics(
pics.HeadOffset = GetActorDrawOffset(
pics.Head, BODY_PART_HEAD, c->Class->Sprites, anim, frame, dir,
GUNSTATE_READY);
if (c->Class->HasHair)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
pics.Hair = GetHairPic(c->Hair, headDir, grimace, colors);
if (c->Class->HasHeadParts[hp])
{
pics.HeadParts[hp] = GetHeadPartPic(c->HeadParts[hp], hp, headDir, grimace, colors);
pics.HeadPartOffsets[hp] = GetActorDrawOffset(
pics.HeadParts[hp], BODY_PART_HEAD, c->Class->Sprites, anim, frame, dir,
GUNSTATE_READY);
}
}
pics.HairOffset = GetActorDrawOffset(
pics.Hair, BODY_PART_HAIR, c->Class->Sprites, anim, frame, dir,
GUNSTATE_READY);
// Gun
for (int i = 0; i < numBarrels; i++)
@@ -399,8 +406,20 @@ static void ReorderPics(
pics->OrderedOffsets[bp] = pics->HeadOffset;
break;
case BODY_PART_HAIR:
pics->OrderedPics[bp] = pics->Hair;
pics->OrderedOffsets[bp] = pics->HairOffset;
pics->OrderedPics[bp] = pics->HeadParts[HEAD_PART_HAIR];
pics->OrderedOffsets[bp] = pics->HeadPartOffsets[HEAD_PART_HAIR];
break;
case BODY_PART_FACEHAIR:
pics->OrderedPics[bp] = pics->HeadParts[HEAD_PART_FACEHAIR];
pics->OrderedOffsets[bp] = pics->HeadPartOffsets[HEAD_PART_FACEHAIR];
break;
case BODY_PART_HAT:
pics->OrderedPics[bp] = pics->HeadParts[HEAD_PART_HAT];
pics->OrderedOffsets[bp] = pics->HeadPartOffsets[HEAD_PART_HAT];
break;
case BODY_PART_GLASSES:
pics->OrderedPics[bp] = pics->HeadParts[HEAD_PART_GLASSES];
pics->OrderedOffsets[bp] = pics->HeadPartOffsets[HEAD_PART_GLASSES];
break;
case BODY_PART_BODY:
pics->OrderedPics[bp] = pics->Body;
@@ -538,11 +557,11 @@ const Pic *GetHeadPic(
PicManagerGetCharSprites(&gPicManager, c->HeadSprites, colors);
return CArrayGet(&ns->pics, idx);
}
const Pic *GetHairPic(
const char *hair, const direction_e dir, const bool isGrimacing,
const Pic *GetHeadPartPic(
const char *name, const HeadPart hp, const direction_e dir, const bool isGrimacing,
const CharColors *colors)
{
if (hair == NULL)
if (name == NULL)
{
return NULL;
}
@@ -550,7 +569,8 @@ const Pic *GetHairPic(
const int idx = (int)dir + row * 8;
// Get or generate masked sprites
char buf[CDOGS_PATH_MAX];
sprintf(buf, "chars/hairs/%s", hair);
const char *subpaths[] = {"hairs", "facehairs", "hats", "glasses"};
sprintf(buf, "chars/%s/%s", subpaths[hp], name);
const NamedSprites *ns =
PicManagerGetCharSprites(&gPicManager, buf, colors);
return CArrayGet(&ns->pics, idx);
@@ -665,14 +685,18 @@ void DrawHead(
PicRender(
head, renderer, drawPos, mask, 0, svec2_one(), SDL_FLIP_NONE,
Rect2iZero());
if (c->Class->HasHair)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
const Pic *hair = GetHairPic(c->Hair, dir, isGrimacing, &c->Colors);
if (hair)
if (c->Class->HasHeadParts[hp])
{
PicRender(
hair, renderer, drawPos, mask, 0, svec2_one(), SDL_FLIP_NONE,
Rect2iZero());
const Pic *pic = GetHeadPartPic(c->HeadParts[hp], hp, dir, isGrimacing, &c->Colors);
if (pic)
{
PicRender(
pic, renderer, drawPos, mask, 0, svec2_one(), SDL_FLIP_NONE,
Rect2iZero());
}
}
}
}

View File

@@ -22,7 +22,7 @@
This file incorporates work covered by the following copyright and
permission notice:
Copyright (c) 2013-2014, 2016-2021 Cong Xu
Copyright (c) 2013-2014, 2016-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -56,9 +56,9 @@
typedef struct
{
const Pic *Head;
struct vec2i HairOffset;
const Pic *Hair;
struct vec2i HeadOffset;
const Pic *HeadParts[HEAD_PART_COUNT];
struct vec2i HeadPartOffsets[HEAD_PART_COUNT];
const Pic *Body;
struct vec2i BodyOffset;
const Pic *Legs;
@@ -85,8 +85,8 @@ void DrawHead(
const Pic *GetHeadPic(
const CharacterClass *c, const direction_e dir, const bool isGrimacing,
const CharColors *colors);
const Pic *GetHairPic(
const char *hair, const direction_e dir, const bool isGrimacing,
const Pic *GetHeadPartPic(
const char *name, const HeadPart hp, const direction_e dir, const bool isGrimacing,
const CharColors *colors);
ActorPics GetCharacterPics(
const Character *c, const direction_e dir, const direction_e legDir,

View File

@@ -286,6 +286,7 @@ void ConvertCharacterColors(
c->Legs = ColorTint(PaletteToColor(cShadePalettes[leg]), tint);
c->Hair = ColorTint(PaletteToColor(cShadePalettes[hair]), tint);
c->Feet = c->Legs;
c->Facehair = c->Hat = c->Glasses = c->Hair;
}
// Hair colour correction; some characters had no hair but now with
@@ -344,7 +345,7 @@ void ConvertCharacter(Character *c, TBadGuy *b)
{
const char *face = IntCharacterFace(b->facePic);
char *newFace = NULL;
CharacterOldFaceToHair(face, &newFace, &c->Hair);
CharacterOldFaceToHeadParts(face, &newFace, c->HeadParts);
c->Class = StrCharacterClass(newFace);
CFREE(newFace);
c->speed = b->speed / 256.0f;

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2014-2016, 2020-2021 Cong Xu
Copyright (c) 2014-2016, 2020-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -63,9 +63,21 @@ NPlayerData NMakePlayerData(const PlayerData *p)
const Character *c = &p->Char;
strcpy(d.Name, p->name);
strcpy(d.CharacterClass, p->Char.Class->Name);
if (p->Char.Hair)
if (p->Char.HeadParts[HEAD_PART_HAIR])
{
strcpy(d.Hair, p->Char.Hair);
strcpy(d.Hair, p->Char.HeadParts[HEAD_PART_HAIR]);
}
if (p->Char.HeadParts[HEAD_PART_FACEHAIR])
{
strcpy(d.Facehair, p->Char.HeadParts[HEAD_PART_FACEHAIR]);
}
if (p->Char.HeadParts[HEAD_PART_HAT])
{
strcpy(d.Hat, p->Char.HeadParts[HEAD_PART_HAT]);
}
if (p->Char.HeadParts[HEAD_PART_GLASSES])
{
strcpy(d.Glasses, p->Char.HeadParts[HEAD_PART_GLASSES]);
}
d.Colors = CharColors2Net(c->Colors);
d.Weapons_count = MAX_WEAPONS;
@@ -143,13 +155,16 @@ NCharColors CharColors2Net(const CharColors c)
{
NCharColors co;
co.has_Skin = co.has_Arms = co.has_Body = co.has_Legs = co.has_Hair =
co.has_Feet = true;
co.has_Feet = co.has_Facehair = co.has_Hat = co.has_Glasses = true;
co.Skin = Color2Net(c.Skin);
co.Arms = Color2Net(c.Arms);
co.Body = Color2Net(c.Body);
co.Legs = Color2Net(c.Legs);
co.Hair = Color2Net(c.Hair);
co.Feet = Color2Net(c.Feet);
co.Facehair = Color2Net(c.Facehair);
co.Hat = Color2Net(c.Hat);
co.Glasses = Color2Net(c.Glasses);
return co;
}
CharColors Net2CharColors(const NCharColors c)
@@ -161,6 +176,9 @@ CharColors Net2CharColors(const NCharColors c)
co.Legs = Net2Color(c.Legs);
co.Hair = Net2Color(c.Hair);
co.Feet = Net2Color(c.Feet);
co.Facehair = Net2Color(c.Facehair);
co.Hat = Net2Color(c.Hat);
co.Glasses = Net2Color(c.Glasses);
return co;
}
void Ammo2Net(pb_size_t *ammoCount, NAmmo *ammo, const CArray *a)

View File

@@ -40,7 +40,7 @@
#define NET_LISTEN_PORT 34219
#define NET_PROTOCOL_VERSION 13
#define NET_PROTOCOL_VERSION 14
// Messages

View File

@@ -54,7 +54,10 @@ void PicManagerInit(PicManager *pm)
pm->sprites = hashmap_new();
pm->customPics = hashmap_new();
pm->customSprites = hashmap_new();
CArrayInit(&pm->hairstyleNames, sizeof(char *));
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CArrayInit(&pm->headPartNames[hp], sizeof(char *));
}
CArrayInit(&pm->wallStyleNames, sizeof(char *));
CArrayInit(&pm->tileStyleNames, sizeof(char *));
CArrayInit(&pm->exitStyleNames, sizeof(char *));
@@ -135,6 +138,22 @@ static void PicManagerAdd(
if (strncmp("chars/", buf, strlen("chars/")) == 0)
{
// All head parts use hair color, so determine
// which head part we are looking at
const char *subfolder = buf + strlen("chars/");
CharColorType headPartColor = CHAR_COLOR_HAIR;
if (strncmp("facehairs/", subfolder, strlen("facehairs/")) == 0)
{
headPartColor = CHAR_COLOR_FACEHAIR;
}
else if (strncmp("hats/", subfolder, strlen("hats/")) == 0)
{
headPartColor = CHAR_COLOR_HAT;
}
else if (strncmp("glasses/", subfolder, strlen("glasses/")) == 0)
{
headPartColor = CHAR_COLOR_GLASSES;
}
// Convert char pics to multichannel version
for (int i = 0; i < pic->size.x * pic->size.y; i++)
{
@@ -147,7 +166,7 @@ static void PicManagerAdd(
}
// Convert character color keyed color to
// greyscale + special alpha
const CharColorType colorType = CharColorTypeFromColor(c);
const CharColorType colorType = CharColorTypeFromColor(c, headPartColor);
color_t converted = c;
if (colorType != CHAR_COLOR_COUNT)
{
@@ -249,7 +268,10 @@ static void FindStylePics(
PicManager *pm, CArray *styleNames, PFany hashmapFunc);
static void FindStyleSprites(
PicManager *pm, CArray *styleNames, PFany hashmapFunc);
static int MaybeAdHairSpriteName(any_t data, any_t item);
static int MaybeAddHairSpriteName(any_t data, any_t item);
static int MaybeAddFacehairSpriteName(any_t data, any_t item);
static int MaybeAddHatSpriteName(any_t data, any_t item);
static int MaybeAddGlassesSpriteName(any_t data, any_t item);
static int MaybeAddWallPicName(any_t data, any_t item);
static int MaybeAddTilePicName(any_t data, any_t item);
static int MaybeAddExitPicName(any_t data, any_t item);
@@ -257,7 +279,10 @@ static int MaybeAddKeyPicName(any_t data, any_t item);
static int MaybeAddDoorPicName(any_t data, any_t item);
static void AfterAdd(PicManager *pm)
{
FindStyleSprites(pm, &pm->hairstyleNames, MaybeAdHairSpriteName);
FindStyleSprites(pm, &pm->headPartNames[HEAD_PART_HAIR], MaybeAddHairSpriteName);
FindStyleSprites(pm, &pm->headPartNames[HEAD_PART_FACEHAIR], MaybeAddFacehairSpriteName);
FindStyleSprites(pm, &pm->headPartNames[HEAD_PART_HAT], MaybeAddHatSpriteName);
FindStyleSprites(pm, &pm->headPartNames[HEAD_PART_GLASSES], MaybeAddGlassesSpriteName);
FindStylePics(pm, &pm->wallStyleNames, MaybeAddWallPicName);
FindStylePics(pm, &pm->tileStyleNames, MaybeAddTilePicName);
FindStylePics(pm, &pm->exitStyleNames, MaybeAddExitPicName);
@@ -344,14 +369,30 @@ static void MaybeAddStyleName(
CSTRDUP(s, buf);
CArrayPushBack(styleNames, &s);
}
static int MaybeAdHairSpriteName(any_t data, any_t item)
static int MaybeAddHeadPartSpriteName(any_t data, any_t item, const HeadPart hp, const char *path)
{
PicManager *pm = data;
MaybeAddStyleName(
((const NamedSprites *)item)->name, "chars/hairs/",
&pm->hairstyleNames);
((const NamedSprites *)item)->name, path,
&pm->headPartNames[hp]);
return MAP_OK;
}
static int MaybeAddHairSpriteName(any_t data, any_t item)
{
return MaybeAddHeadPartSpriteName(data, item, HEAD_PART_HAIR, "chars/hairs/");
}
static int MaybeAddFacehairSpriteName(any_t data, any_t item)
{
return MaybeAddHeadPartSpriteName(data, item, HEAD_PART_FACEHAIR, "chars/facehairs/");
}
static int MaybeAddHatSpriteName(any_t data, any_t item)
{
return MaybeAddHeadPartSpriteName(data, item, HEAD_PART_HAT, "chars/hats/");
}
static int MaybeAddGlassesSpriteName(any_t data, any_t item)
{
return MaybeAddHeadPartSpriteName(data, item, HEAD_PART_GLASSES, "chars/glasses/");
}
static int MaybeAddExitPicName(any_t data, any_t item)
{
// Exit pics should be like:
@@ -434,7 +475,10 @@ static void StyleNamesDestroy(CArray *a)
void PicManagerTerminate(PicManager *pm)
{
PicManagerUnload(pm);
StyleNamesDestroy(&pm->hairstyleNames);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
StyleNamesDestroy(&pm->headPartNames[hp]);
}
StyleNamesDestroy(&pm->wallStyleNames);
StyleNamesDestroy(&pm->tileStyleNames);
StyleNamesDestroy(&pm->exitStyleNames);

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2016, 2018-2019 Cong Xu
Copyright (c) 2013-2016, 2018-2019, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ typedef struct
map_t customPics; // of NamedPic
map_t customSprites; // of NamedSprites
CArray hairstyleNames; // of char *
CArray headPartNames[HEAD_PART_COUNT]; // of char *
CArray wallStyleNames; // of char *
CArray tileStyleNames; // of char *
CArray exitStyleNames; // of char *

View File

@@ -74,12 +74,17 @@ void PlayerDataAddOrUpdate(const NPlayerData pd)
{
p->Char.Class = StrCharacterClass("Jones");
}
CFREE(p->Char.Hair);
p->Char.Hair = NULL;
if (strlen(pd.Hair) > 0)
{
CSTRDUP(p->Char.Hair, pd.Hair);
#define ADDHEADPART(_hp, _pdPart) \
CFREE(p->Char.HeadParts[_hp]); \
p->Char.HeadParts[_hp] = NULL; \
if (strlen(_pdPart) > 0) \
{ \
CSTRDUP(p->Char.HeadParts[_hp], _pdPart); \
}
ADDHEADPART(HEAD_PART_HAIR, pd.Hair);
ADDHEADPART(HEAD_PART_FACEHAIR, pd.Facehair);
ADDHEADPART(HEAD_PART_HAT, pd.Hat);
ADDHEADPART(HEAD_PART_GLASSES, pd.Glasses);
p->Char.Colors = Net2CharColors(pd.Colors);
for (int i = 0; i < (int)pd.Weapons_count; i++)
{
@@ -155,9 +160,21 @@ NPlayerData PlayerDataDefault(const int idx)
{
strcpy(pd.Name, t->name);
strcpy(pd.CharacterClass, t->CharClassName);
if (t->Hair != NULL)
if (t->HeadParts[HEAD_PART_HAIR] != NULL)
{
strcpy(pd.Hair, t->Hair);
strcpy(pd.Hair, t->HeadParts[HEAD_PART_HAIR]);
}
if (t->HeadParts[HEAD_PART_FACEHAIR] != NULL)
{
strcpy(pd.Facehair, t->HeadParts[HEAD_PART_FACEHAIR]);
}
if (t->HeadParts[HEAD_PART_HAT] != NULL)
{
strcpy(pd.Hat, t->HeadParts[HEAD_PART_HAT]);
}
if (t->HeadParts[HEAD_PART_GLASSES] != NULL)
{
strcpy(pd.Glasses, t->HeadParts[HEAD_PART_GLASSES]);
}
pd.Colors = CharColors2Net(t->Colors);
}
@@ -172,41 +189,42 @@ NPlayerData PlayerDataDefault(const int idx)
pd.Colors.Arms = Color2Net(colorLightBlue);
pd.Colors.Body = Color2Net(colorLightBlue);
pd.Colors.Legs = Color2Net(colorLightBlue);
pd.Colors.Hair = Color2Net(colorLightBlue);
pd.Colors.Feet = Color2Net(colorLightBlue);
break;
case 1:
strcpy(pd.Name, "Ice");
strcpy(pd.CharacterClass, "Jones");
strcpy(pd.Hair, "shades");
strcpy(pd.Glasses, "shades");
pd.Colors.Skin = Color2Net(colorDarkSkin);
pd.Colors.Arms = Color2Net(colorRed);
pd.Colors.Body = Color2Net(colorRed);
pd.Colors.Legs = Color2Net(colorRed);
pd.Colors.Hair = Color2Net(colorBlack);
pd.Colors.Feet = Color2Net(colorRed);
pd.Colors.Glasses = Color2Net(colorBlack);
break;
case 2:
strcpy(pd.Name, "Warbaby");
strcpy(pd.CharacterClass, "Jones");
strcpy(pd.Hair, "beret");
strcpy(pd.Hat, "beret");
pd.Colors.Skin = Color2Net(colorSkin);
pd.Colors.Arms = Color2Net(colorGreen);
pd.Colors.Body = Color2Net(colorGreen);
pd.Colors.Legs = Color2Net(colorGreen);
pd.Colors.Hair = Color2Net(colorRed);
pd.Colors.Feet = Color2Net(colorGreen);
pd.Colors.Hat = Color2Net(colorRed);
break;
case 3:
strcpy(pd.Name, "Han");
strcpy(pd.CharacterClass, "Jones");
strcpy(pd.Hair, "hogan");
strcpy(pd.Hair, "rattail");
strcpy(pd.Facehair, "handlebar");
pd.Colors.Skin = Color2Net(colorAsianSkin);
pd.Colors.Arms = Color2Net(colorYellow);
pd.Colors.Body = Color2Net(colorYellow);
pd.Colors.Legs = Color2Net(colorYellow);
pd.Colors.Hair = Color2Net(colorYellow);
pd.Colors.Feet = Color2Net(colorYellow);
pd.Colors.Facehair = Color2Net(colorYellow);
break;
default:
// Set up player N template

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2014, 2016-2020 Cong Xu
Copyright (c) 2013-2014, 2016-2020, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@
#include <emscripten.h>
#endif
#define VERSION 3
#define VERSION 4
PlayerTemplates gPlayerTemplates;
@@ -57,12 +57,22 @@ static void LoadPlayerTemplate(
{
char *face;
CSTRDUP(face, t.CharClassName);
CharacterOldFaceToHair(t.CharClassName, &t.CharClassName, &t.Hair);
CharacterOldFaceToHeadParts(t.CharClassName, &t.CharClassName, t.HeadParts);
CFREE(face);
}
else
{
LoadStr(&t.Hair, node, "HairType");
LoadStr(&t.HeadParts[HEAD_PART_HAIR], node, "HairType");
if (version < 4)
{
CharacterOldHairToHeadParts(t.HeadParts);
}
else
{
LoadStr(&t.HeadParts[HEAD_PART_FACEHAIR], node, "FacehairType");
LoadStr(&t.HeadParts[HEAD_PART_HAT], node, "HatType");
LoadStr(&t.HeadParts[HEAD_PART_GLASSES], node, "GlassesType");
}
}
// Colors
if (version == 1)
@@ -84,11 +94,19 @@ static void LoadPlayerTemplate(
LoadColor(&t.Colors.Legs, node, "Legs");
LoadColor(&t.Colors.Hair, node, "Hair");
}
t.Colors.Feet = t.Colors.Legs;
if (version >= 3)
if (version < 3)
{
LoadColor(&t.Colors.Feet, node, "Feet");
t.Colors.Feet = t.Colors.Legs;
}
LoadColor(&t.Colors.Feet, node, "Feet");
if (version < 4)
{
t.Colors.Facehair = t.Colors.Hat = t.Colors.Glasses = t.Colors.Hair;
}
LoadColor(&t.Colors.Facehair, node, "Facehair");
LoadColor(&t.Colors.Hat, node, "Hat");
LoadColor(&t.Colors.Glasses, node, "Glasses");
CArrayPushBack(templates, &t);
LOG(LM_MAIN, LL_DEBUG, "loaded player template %s (%s)", t.name,
t.CharClassName);
@@ -152,7 +170,10 @@ void PlayerTemplatesClear(CArray *classes)
{
CA_FOREACH(PlayerTemplate, pt, *classes)
CFREE(pt->CharClassName);
CFREE(pt->Hair);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CFREE(pt->HeadParts[hp]);
}
CA_FOREACH_END()
CArrayClear(classes);
}
@@ -180,16 +201,35 @@ PlayerTemplate *PlayerTemplateGetById(PlayerTemplates *pt, const int id)
static void SavePlayerTemplate(const PlayerTemplate *t, json_t *templates)
{
json_t *template = json_new_object();
AddStringPair(template, "Name", t->name);
AddStringPair(template, "Face", t->CharClassName);
AddColorPair(template, "Body", t->Colors.Body);
AddColorPair(template, "Arms", t->Colors.Arms);
AddColorPair(template, "Legs", t->Colors.Legs);
AddColorPair(template, "Skin", t->Colors.Skin);
AddColorPair(template, "Hair", t->Colors.Hair);
AddColorPair(template, "Feet", t->Colors.Feet);
json_insert_child(templates, template);
json_t *node = json_new_object();
AddStringPair(node, "Name", t->name);
AddStringPair(node, "Face", t->CharClassName);
if (t->HeadParts[HEAD_PART_HAIR])
{
AddStringPair(node, "HairType", t->HeadParts[HEAD_PART_HAIR]);
}
if (t->HeadParts[HEAD_PART_FACEHAIR])
{
AddStringPair(node, "FacehairType", t->HeadParts[HEAD_PART_FACEHAIR]);
}
if (t->HeadParts[HEAD_PART_HAT])
{
AddStringPair(node, "HatType", t->HeadParts[HEAD_PART_HAT]);
}
if (t->HeadParts[HEAD_PART_GLASSES])
{
AddStringPair(node, "GlassesType", t->HeadParts[HEAD_PART_GLASSES]);
}
AddColorPair(node, "Body", t->Colors.Body);
AddColorPair(node, "Arms", t->Colors.Arms);
AddColorPair(node, "Legs", t->Colors.Legs);
AddColorPair(node, "Skin", t->Colors.Skin);
AddColorPair(node, "Hair", t->Colors.Hair);
AddColorPair(node, "Facehair", t->Colors.Facehair);
AddColorPair(node, "Hat", t->Colors.Hat);
AddColorPair(node, "Glasses", t->Colors.Glasses);
AddColorPair(node, "Feet", t->Colors.Feet);
json_insert_child(templates, node);
}
void PlayerTemplatesSave(const PlayerTemplates *pt)
{
@@ -234,17 +274,55 @@ bail:
}
}
void PlayerTemplateToPlayerData(PlayerData *p, const PlayerTemplate *t)
{
memset(p->name, 0, sizeof p->name);
strcpy(p->name, t->name);
p->Char.Class = StrCharacterClass(t->CharClassName);
if (p->Char.Class == NULL)
{
p->Char.Class = StrCharacterClass("Jones");
}
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CFREE(p->Char.HeadParts[hp]);
p->Char.HeadParts[hp] = NULL;
if (t->HeadParts[hp])
{
CSTRDUP(p->Char.HeadParts[hp], t->HeadParts[hp]);
}
}
p->Char.Colors = t->Colors;
}
static void PlayerTemplateFromCharacter(PlayerTemplate *t, const Character *c)
{
CFREE(t->CharClassName);
CSTRDUP(t->CharClassName, c->Class->Name);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
if (c->HeadParts[hp])
{
CFREE(t->HeadParts[hp]);
CSTRDUP(t->HeadParts[hp], c->HeadParts[hp]);
}
}
t->Colors = c->Colors;
}
void PlayerTemplateFromPlayerData(PlayerTemplate *t, const PlayerData *p)
{
memset(t->name, 0, sizeof t->name);
strcpy(t->name, p->name);
PlayerTemplateFromCharacter(t, &p->Char);
}
void PlayerTemplateAddCharacter(CArray *classes, const Character *c)
{
PlayerTemplate t;
memset(&t, 0, sizeof t);
strncpy(t.name, c->PlayerTemplateName, PLAYER_NAME_MAXLEN - 1);
CSTRDUP(t.CharClassName, c->Class->Name);
if (c->Hair != NULL)
{
CSTRDUP(t.Hair, c->Hair);
}
t.Colors = c->Colors;
PlayerTemplateFromCharacter(&t, c);
CArrayPushBack(classes, &t);
LOG(LM_MAIN, LL_DEBUG, "loaded player template from characters %s (%s)",
t.name, t.CharClassName);

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2014, 2016-2020 Cong Xu
Copyright (c) 2013-2014, 2016-2020, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
#include "character.h"
#include "character_class.h"
#include "player.h"
#define PLAYER_NAME_MAXLEN 20
#define PLAYER_TEMPLATE_FILE "players.cnf"
@@ -38,7 +39,7 @@ typedef struct
{
char name[PLAYER_NAME_MAXLEN];
char *CharClassName;
char *Hair;
char *HeadParts[HEAD_PART_COUNT];
CharColors Colors;
} PlayerTemplate;
@@ -56,4 +57,6 @@ void PlayerTemplatesTerminate(PlayerTemplates *pt);
PlayerTemplate *PlayerTemplateGetById(PlayerTemplates *pt, const int id);
void PlayerTemplatesSave(const PlayerTemplates *pt);
void PlayerTemplateToPlayerData(PlayerData *p, const PlayerTemplate *t);
void PlayerTemplateFromPlayerData(PlayerTemplate *t, const PlayerData *p);
void PlayerTemplateAddCharacter(CArray *classes, const Character *c);

View File

@@ -600,10 +600,26 @@ bool IntsEqual(const void *v1, const void *v2)
return *(const int *)v1 == *(const int *)v2;
}
const char *HeadPartStr(const HeadPart hp)
{
switch (hp)
{
T2S(HEAD_PART_HAIR, "Hair");
T2S(HEAD_PART_FACEHAIR, "Facial Hair");
T2S(HEAD_PART_HAT, "Hat");
T2S(HEAD_PART_GLASSES, "Glasses");
default:
return "";
}
}
BodyPart StrBodyPart(const char *s)
{
S2T(BODY_PART_HEAD, "head");
S2T(BODY_PART_HAIR, "hair");
S2T(BODY_PART_FACEHAIR, "facehair");
S2T(BODY_PART_HAT, "hat");
S2T(BODY_PART_GLASSES, "glasses");
S2T(BODY_PART_BODY, "body");
S2T(BODY_PART_LEGS, "legs");
S2T(BODY_PART_GUN_R, "gun_r");

View File

@@ -22,7 +22,7 @@
This file incorporates work covered by the following copyright and
permission notice:
Copyright (c) 2013-2017, 2019-2022 Cong Xu
Copyright (c) 2013-2017, 2019-2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -214,10 +214,24 @@ bool IntsEqual(const void *v1, const void *v2);
((_low) + ((double)rand() / RAND_MAX * ((_high) - (_low))))
#define RAND_BOOL() (RAND_INT(0, 1) == 0)
typedef enum
{
HEAD_PART_HAIR,
HEAD_PART_FACEHAIR,
HEAD_PART_HAT,
HEAD_PART_GLASSES,
HEAD_PART_COUNT
} HeadPart; // cranial accessories
const char *HeadPartStr(const HeadPart hp);
typedef enum
{
BODY_PART_HEAD,
BODY_PART_HAIR,
BODY_PART_FACEHAIR,
BODY_PART_HAT,
BODY_PART_GLASSES,
BODY_PART_BODY,
BODY_PART_LEGS,
BODY_PART_GUN_R,

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2017-2021 Cong Xu
Copyright (c) 2017-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -42,13 +42,13 @@ typedef struct
CampaignSetting *Setting;
bool *FileChanged;
char *CharacterClassNames;
char *HairNames;
char *HeadPartNames[HEAD_PART_COUNT];
char *GunNames;
char *PickupNames;
CArray texidsChars; // of GLuint[BODY_PART_COUNT]
GLuint texidsPreview[BODY_PART_COUNT];
CArray texIdsCharClasses; // of GLuint
CArray texIdsHairs; // of GLuint
CArray texIdsHeadParts[HEAD_PART_COUNT]; // of GLuint
CArray texIdsGuns; // of GLuint
CArray texIdsPickups; // of GLuint
Animation anim;
@@ -58,7 +58,23 @@ typedef struct
} EditorContext;
static const char *IndexCharacterClassName(const int i);
static const char *IndexHairName(const int i);
static const char *IndexHeadPartName(const int i, const HeadPart hp);
static const char *IndexHairName(const int i)
{
return IndexHeadPartName(i, HEAD_PART_HAIR);
}
static const char *IndexFacehairName(const int i)
{
return IndexHeadPartName(i, HEAD_PART_FACEHAIR);
}
static const char *IndexHatName(const int i)
{
return IndexHeadPartName(i, HEAD_PART_HAT);
}
static const char *IndexGlassesName(const int i)
{
return IndexHeadPartName(i, HEAD_PART_GLASSES);
}
static const char *IndexGunName(const int i);
static const char *IndexPickupName(const int i);
static const WeaponClass *IndexWeaponClassReal(const int i);
@@ -93,8 +109,14 @@ void CharEditor(
ec.FileChanged = fileChanged;
ec.CharacterClassNames =
GetClassNames(NumCharacterClasses(), IndexCharacterClassName);
ec.HairNames =
GetClassNames(gPicManager.hairstyleNames.size, IndexHairName);
const char *(*indexHeadPartFuncs[HEAD_PART_COUNT])(int) = {
IndexHairName, IndexFacehairName, IndexHatName, IndexGlassesName
};
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
ec.HeadPartNames[hp] =
GetClassNames(gPicManager.headPartNames[hp].size, *indexHeadPartFuncs[hp]);
}
ec.GunNames = GetClassNames(NumGuns(), IndexGunName);
ec.PickupNames = GetClassNames(NumPickups(), IndexPickupName);
@@ -115,11 +137,14 @@ void CharEditor(
LoadTexFromPic(*texid, GetHeadPic(c, DIRECTION_DOWN, false, &cc));
CA_FOREACH_END()
TexArrayInit(&ec.texIdsHairs, gPicManager.hairstyleNames.size);
CA_FOREACH(const GLuint, texid, ec.texIdsHairs)
const char *hair = IndexHairName(_ca_index);
LoadTexFromPic(*texid, GetHairPic(hair, DIRECTION_DOWN, false, &cc));
CA_FOREACH_END()
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
TexArrayInit(&ec.texIdsHeadParts[hp], gPicManager.headPartNames[hp].size);
CA_FOREACH(const GLuint, texid, ec.texIdsHeadParts[hp])
const char *name = IndexHeadPartName(_ca_index, hp);
LoadTexFromPic(*texid, GetHeadPartPic(name, hp, DIRECTION_DOWN, false, &cc));
CA_FOREACH_END()
}
TexArrayInit(&ec.texIdsGuns, NumGuns());
CA_FOREACH(const GLuint, texid, ec.texIdsGuns)
@@ -144,22 +169,27 @@ void CharEditor(
NKWindow(cfg);
CFREE(ec.CharacterClassNames);
CFREE(ec.HairNames);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CFREE(ec.HeadPartNames[hp]);
}
CFREE(ec.GunNames);
CFREE(ec.PickupNames);
glDeleteTextures(
(GLsizei)(BODY_PART_COUNT * ec.texidsChars.size), ec.texidsChars.data);
CArrayTerminate(&ec.texidsChars);
glDeleteTextures(BODY_PART_COUNT, ec.texidsPreview);
glDeleteTextures(
(GLsizei)ec.texIdsCharClasses.size, ec.texIdsCharClasses.data);
TexArrayTerminate(&ec.texIdsCharClasses);
glDeleteTextures((GLsizei)ec.texIdsHairs.size, ec.texIdsHairs.data);
TexArrayTerminate(&ec.texIdsHairs);
glDeleteTextures((GLsizei)ec.texIdsGuns.size, ec.texIdsGuns.data);
TexArrayTerminate(&ec.texIdsGuns);
glDeleteTextures((GLsizei)ec.texIdsPickups.size, ec.texIdsPickups.data);
TexArrayTerminate(&ec.texIdsPickups);
#define DELTEX(_tx) \
glDeleteTextures( \
(GLsizei)(_tx).size, (_tx).data); \
TexArrayTerminate(&(_tx));
DELTEX(ec.texIdsCharClasses);
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
DELTEX(ec.texIdsHeadParts[hp]);
}
DELTEX(ec.texIdsGuns);
DELTEX(ec.texIdsPickups);
}
static const char *IndexCharacterClassName(const int i)
@@ -167,9 +197,9 @@ static const char *IndexCharacterClassName(const int i)
const CharacterClass *c = IndexCharacterClass(i);
return c->Name;
}
static const char *IndexHairName(const int i)
static const char *IndexHeadPartName(const int i, const HeadPart hp)
{
return *(char **)CArrayGet(&gPicManager.hairstyleNames, i);
return *(char **)CArrayGet(&gPicManager.headPartNames[hp], i);
}
static int NumCharacterClasses(void)
{
@@ -333,7 +363,7 @@ static int DrawClassSelection(
struct nk_context *ctx, EditorContext *ec, const char *label,
const GLuint *texids, const char *items, const int selected,
const size_t len);
static int HairIndex(const char *hair);
static int HeadPartIndex(const char *name, const HeadPart hp);
static void DrawFlag(
struct nk_context *ctx, EditorContext *ec, const char *label,
const int flag, const char *tooltip);
@@ -499,32 +529,33 @@ static bool Draw(SDL_Window *win, struct nk_context *ctx, void *data)
NumCharacterClasses());
ec->Char->Class = IndexCharacterClass(selectedClass);
nk_layout_row_dynamic(ctx, ROW_HEIGHT, 1);
int hasHair = ec->Char->Hair != NULL;
nk_checkbox_label(ctx, "Has Hair", &hasHair);
if (hasHair)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
nk_layout_row(ctx, NK_DYNAMIC, ROW_HEIGHT, 2, colRatios);
const int currentHair = (int)HairIndex(ec->Char->Hair);
int selectedHair = DrawClassSelection(
ctx, ec, "Hair:", ec->texIdsHairs.data, ec->HairNames,
currentHair, gPicManager.hairstyleNames.size);
if (selectedHair == -1)
nk_layout_row_dynamic(ctx, ROW_HEIGHT, 1);
int hasStyle = ec->Char->HeadParts[hp] != NULL;
char buf[256];
sprintf(buf, "Has %s", HeadPartStr(hp));
nk_checkbox_label(ctx, buf, &hasStyle);
if (hasStyle)
{
selectedHair = 0;
nk_layout_row(ctx, NK_DYNAMIC, ROW_HEIGHT, 2, colRatios);
const int current = HeadPartIndex(ec->Char->HeadParts[hp], hp);
sprintf(buf, "%s:", HeadPartStr(hp));
int selected = DrawClassSelection(ctx, ec, buf, ec->texIdsHeadParts[hp].data, ec->HeadPartNames[hp], current, gPicManager.headPartNames[hp].size);
if (selected == -1)
{
selected = 0;
}
if (current != selected)
{
CharacterSetHeadPart(ec->Char, hp, IndexHeadPartName(selected, hp));
}
}
if (currentHair != selectedHair)
else
{
CFREE(ec->Char->Hair);
CSTRDUP(ec->Char->Hair, IndexHairName(selectedHair));
CharacterSetHeadPart(ec->Char, hp, NULL);
}
}
else
{
CFREE(ec->Char->Hair);
ec->Char->Hair = NULL;
}
// Character colours
nk_layout_row(ctx, NK_DYNAMIC, ROW_HEIGHT, 2, colRatios);
@@ -536,6 +567,18 @@ static bool Draw(SDL_Window *win, struct nk_context *ctx, void *data)
{
*ec->FileChanged = true;
}
if (ColorPicker(ctx, ROW_HEIGHT, "Facial Hair:", &ec->Char->Colors.Facehair))
{
*ec->FileChanged = true;
}
if (ColorPicker(ctx, ROW_HEIGHT, "Hat:", &ec->Char->Colors.Hat))
{
*ec->FileChanged = true;
}
if (ColorPicker(ctx, ROW_HEIGHT, "Glasses:", &ec->Char->Colors.Glasses))
{
*ec->FileChanged = true;
}
if (ColorPicker(ctx, ROW_HEIGHT, "Arms:", &ec->Char->Colors.Arms))
{
*ec->FileChanged = true;
@@ -691,9 +734,10 @@ static void AddCharacter(EditorContext *ec, const int cloneIdx)
{
CSTRDUP(ec->Char->PlayerTemplateName, clone->PlayerTemplateName);
}
if (clone->Hair)
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
CSTRDUP(ec->Char->Hair, clone->Hair);
ec->Char->HeadParts[hp] = NULL;
CharacterSetHeadPart(ec->Char, hp, clone->HeadParts[hp]);
}
CMALLOC(ec->Char->bot, sizeof *ec->Char->bot);
memcpy(ec->Char->bot, clone->bot, sizeof *ec->Char->bot);
@@ -708,6 +752,9 @@ static void AddCharacter(EditorContext *ec, const int cloneIdx)
ec->Char->Colors.Legs = colorDarkGray;
ec->Char->Colors.Hair = colorBlack;
ec->Char->Colors.Feet = colorDarkGray;
ec->Char->Colors.Facehair = colorDarkGray;
ec->Char->Colors.Hat = colorDarkGray;
ec->Char->Colors.Glasses = colorDarkGray;
ec->Char->speed = 1;
ec->Char->Gun = StrWeaponClass("Machine gun");
ec->Char->maxHealth = 40;
@@ -788,14 +835,14 @@ static int DrawClassSelection(
return selectedNew;
}
static int HairIndex(const char *hair)
static int HeadPartIndex(const char *name, const HeadPart hp)
{
if (hair == NULL)
if (name == NULL)
{
return -1;
}
CA_FOREACH(const char *, hairstyleName, gPicManager.hairstyleNames)
if (strcmp(*hairstyleName, hair) == 0)
CA_FOREACH(const char *, hpName, gPicManager.headPartNames[hp])
if (strcmp(*hpName, name) == 0)
{
return _ca_index;
}

View File

@@ -2,7 +2,7 @@
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2013-2016, 2018-2021 Cong Xu
Copyright (c) 2013-2016, 2018-2021, 2023 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -211,7 +211,7 @@ static int HandleInputNameMenu(int cmd, void *data)
}
static void PostInputRotatePlayer(menu_t *menu, int cmd, void *data);
static void CheckReenableHairHatMenu(menu_t *menu, void *data);
static void CheckReenableHeadPartMenu(menu_t *menu, void *data);
static void PostInputFaceMenu(menu_t *menu, int cmd, void *data);
static menu_t *CreateFaceMenu(MenuDisplayPlayerData *data)
@@ -246,32 +246,34 @@ static void PostInputFaceMenu(menu_t *menu, int cmd, void *data)
PostInputRotatePlayer(menu, cmd, data);
}
static void PostInputHairMenu(menu_t *menu, int cmd, void *data);
static menu_t *CreateHairMenu(MenuDisplayPlayerData *data)
static void PostInputHeadPartMenu(menu_t *menu, int cmd, void *data);
static menu_t *CreateHeadPartMenu(PlayerSelectMenuData *data, const HeadPart hp)
{
menu_t *menu = MenuCreateNormal("Hair/hat", "", MENU_TYPE_NORMAL, 0);
menu_t *menu = MenuCreateNormal(HeadPartStr(hp), "", MENU_TYPE_NORMAL, 0);
menu->u.normal.maxItems = 11;
MenuAddSubmenu(menu, MenuCreateBack("(None)"));
CA_FOREACH(const char *, h, gPicManager.hairstyleNames)
CA_FOREACH(const char *, h, gPicManager.headPartNames[hp])
MenuAddSubmenu(menu, MenuCreateBack(*h));
CA_FOREACH_END()
MenuSetPostInputFunc(menu, PostInputHairMenu, data);
HeadPartMenuData *hpmd = &data->headPartData[hp];
hpmd->PlayerUID = data->display.PlayerUID;
hpmd->HP = hp;
MenuSetPostInputFunc(menu, PostInputHeadPartMenu, hpmd);
return menu;
}
static void PostInputHairMenu(menu_t *menu, int cmd, void *data)
static void PostInputHeadPartMenu(menu_t *menu, int cmd, void *data)
{
const MenuDisplayPlayerData *d = data;
const HeadPartMenuData *d = data;
// Change player hairstyle based on current menu selection
PlayerData *p = PlayerDataGetByUID(d->PlayerUID);
Character *c = &p->Char;
CFREE(c->Hair);
c->Hair = NULL;
const char *hpName = NULL;
if (menu->u.normal.index > 0)
{
const char **hair =
CArrayGet(&gPicManager.hairstyleNames, menu->u.normal.index - 1);
CSTRDUP(c->Hair, *hair);
hpName =
*(const char **)CArrayGet(&gPicManager.headPartNames[d->HP], menu->u.normal.index - 1);
}
CharacterSetHeadPart(c, d->HP, hpName);
PostInputRotatePlayer(menu, cmd, data);
}
@@ -433,20 +435,7 @@ static void PostInputLoadTemplate(menu_t *menu, int cmd, void *data)
PlayerData *p = PlayerDataGetByUID(d->display.PlayerUID);
const PlayerTemplate *t =
PlayerTemplateGetById(&gPlayerTemplates, menu->u.normal.index);
memset(p->name, 0, sizeof p->name);
strcpy(p->name, t->name);
p->Char.Class = StrCharacterClass(t->CharClassName);
if (p->Char.Class == NULL)
{
p->Char.Class = StrCharacterClass("Jones");
}
CFREE(p->Char.Hair);
p->Char.Hair = NULL;
if (t->Hair)
{
CSTRDUP(p->Char.Hair, t->Hair);
}
p->Char.Colors = t->Colors;
PlayerTemplateToPlayerData(p, t);
}
}
@@ -498,16 +487,7 @@ static void PostInputSaveTemplate(menu_t *menu, int cmd, void *data)
t = CArrayGet(
&gPlayerTemplates.Classes, gPlayerTemplates.Classes.size - 1);
}
memset(t->name, 0, sizeof t->name);
strcpy(t->name, p->name);
CFREE(t->CharClassName);
CSTRDUP(t->CharClassName, p->Char.Class->Name);
if (p->Char.Hair)
{
CFREE(t->Hair);
CSTRDUP(t->Hair, p->Char.Hair);
}
t->Colors = p->Char.Colors;
PlayerTemplateFromPlayerData(t, p);
PlayerTemplatesSave(&gPlayerTemplates);
}
@@ -627,7 +607,10 @@ static menu_t *CreateCustomizeMenu(
menu_t *menu = MenuCreateNormal(name, "", MENU_TYPE_NORMAL, 0);
MenuAddSubmenu(menu, CreateFaceMenu(&data->display));
MenuAddSubmenu(menu, CreateHairMenu(&data->display));
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
MenuAddSubmenu(menu, CreateHeadPartMenu(data, hp));
}
MenuAddSubmenu(
menu, CreateColorMenu(
@@ -637,6 +620,18 @@ static menu_t *CreateCustomizeMenu(
menu, CreateColorMenu(
"Hair Color", &data->hairData, data->ms, CHAR_COLOR_HAIR,
data->display.PlayerUID));
MenuAddSubmenu(
menu, CreateColorMenu(
"Facial Hair Color", &data->facehairData, data->ms, CHAR_COLOR_FACEHAIR,
data->display.PlayerUID));
MenuAddSubmenu(
menu, CreateColorMenu(
"Hat Color", &data->hatData, data->ms, CHAR_COLOR_HAT,
data->display.PlayerUID));
MenuAddSubmenu(
menu, CreateColorMenu(
"Glasses Color", &data->glassesData, data->ms, CHAR_COLOR_GLASSES,
data->display.PlayerUID));
MenuAddSubmenu(
menu, CreateColorMenu(
"Arms Color", &data->armsData, data->ms, CHAR_COLOR_ARMS,
@@ -659,7 +654,7 @@ static menu_t *CreateCustomizeMenu(
MenuSetPostInputFunc(menu, PostInputRotatePlayer, &data->display);
MenuSetPostEnterFunc(
menu, CheckReenableHairHatMenu, &data->display, false);
menu, CheckReenableHeadPartMenu, &data->display, false);
return menu;
}
@@ -690,11 +685,20 @@ static void PostInputRotatePlayer(menu_t *menu, int cmd, void *data)
SoundPlay(&gSoundDevice, StrSound(buf));
}
}
static void CheckReenableHairHatMenu(menu_t *menu, void *data)
static void CheckReenableHeadPartMenu(menu_t *menu, void *data)
{
menu_t *hairMenu = MenuGetSubmenuByName(menu, "Hair/hat");
CASSERT(hairMenu, "cannot find menu");
MenuDisplayPlayerData *d = data;
const PlayerData *p = PlayerDataGetByUID(d->PlayerUID);
hairMenu->isDisabled = !p->Char.Class->HasHair;
char buf[256];
for (HeadPart hp = HEAD_PART_HAIR; hp < HEAD_PART_COUNT; hp++)
{
const bool hasPart = p->Char.Class->HasHeadParts[hp];
menu_t *submenu = MenuGetSubmenuByName(menu, HeadPartStr(hp));
CASSERT(submenu, "cannot find menu");
submenu->isDisabled = !hasPart;
sprintf(buf, "%s Color", HeadPartStr(hp));
submenu = MenuGetSubmenuByName(menu, buf);
CASSERT(submenu, "cannot find menu");
submenu->isDisabled = !hasPart;
}
}

View File

@@ -34,6 +34,11 @@
#include "menu_utils.h"
#include "namegen.h"
typedef struct
{
int PlayerUID;
HeadPart HP;
} HeadPartMenuData;
typedef struct
{
CharColorType Type;
@@ -47,12 +52,16 @@ typedef struct
MenuDisplayPlayerData display;
const MenuSystem *ms;
int nameMenuSelection;
HeadPartMenuData headPartData[HEAD_PART_COUNT];
ColorMenuData skinData;
ColorMenuData hairData;
ColorMenuData armsData;
ColorMenuData bodyData;
ColorMenuData legsData;
ColorMenuData feetData;
ColorMenuData facehairData;
ColorMenuData hatData;
ColorMenuData glassesData;
const NameGen *nameGenerator;
} PlayerSelectMenuData;
typedef struct

View File

@@ -6,6 +6,9 @@ NCampaignDef.Path max_size:4096
NPlayerData.Name max_size:20
NPlayerData.CharacterClass max_size:128
NPlayerData.Hair max_size:128
NPlayerData.Facehair max_size:128
NPlayerData.Hat max_size:128
NPlayerData.Glasses max_size:128
NPlayerData.Weapons max_size:128
NPlayerData.Weapons max_count:3
NPlayerData.Ammo max_count:128

View File

@@ -1,5 +1,5 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
/* Generated by nanopb-0.4.8-dev */
#include "msg.pb.h"
#if PB_PROTO_HEADER_VERSION != 40

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,9 @@ message NCharColors {
NColor Legs = 4;
NColor Hair = 5;
NColor Feet = 6;
NColor Facehair = 7;
NColor Hat = 8;
NColor Glasses = 9;
}
message NPlayerStats {
@@ -49,16 +52,19 @@ message NPlayerData {
string Name = 1;
string CharacterClass = 2;
string Hair = 3;
NCharColors Colors = 4;
repeated string Weapons = 5;
uint32 Lives = 6;
NPlayerStats Stats = 7;
NPlayerStats Totals = 8;
uint32 MaxHealth = 9;
uint32 LastMission = 10;
uint32 UID = 11;
repeated NAmmo Ammo = 12;
uint32 HP = 13;
string Facehair = 4;
string Hat = 5;
string Glasses = 6;
NCharColors Colors = 7;
repeated string Weapons = 8;
uint32 Lives = 9;
NPlayerStats Stats = 10;
NPlayerStats Totals = 11;
uint32 MaxHealth = 12;
uint32 LastMission = 13;
uint32 UID = 14;
repeated NAmmo Ammo = 15;
uint32 HP = 16;
}
message NPlayerRemove {