ADDED Makefile
Index: Makefile
==================================================================
--- /dev/null
+++ Makefile
@@ -0,0 +1,5 @@
+SUBDIRS = enet src
+
+src: enet
+
+include buildsys.mk
ADDED autogen.sh
Index: autogen.sh
==================================================================
--- /dev/null
+++ autogen.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+
+# Set a version for OpenBSD
+if test x"$(uname -s)" = x"OpenBSD"; then
+ : ${AUTOCONF_VERSION:=2.71}
+ : ${AUTOMAKE_VERSION:=1.16}
+ export AUTOCONF_VERSION AUTOMAKE_VERSION
+fi
+
+aclocal -I build-aux/m4
+autoconf
ADDED build-aux/config.guess
Index: build-aux/config.guess
==================================================================
--- /dev/null
+++ build-aux/config.guess
@@ -0,0 +1,1807 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2023 Free Software Foundation, Inc.
+
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-08-22'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see .
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
+#
+# Please send patches to .
+
+
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system '$me' is run on.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2023 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try '$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+# Just in case it came from the environment.
+GUESS=
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+ # prevent multiple calls if $tmp is already set
+ test "$tmp" && return 0
+ : "${TMPDIR=/tmp}"
+ # shellcheck disable=SC2039,SC3028
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+ dummy=$tmp/dummy
+ case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+ ,,) echo "int x;" > "$dummy.c"
+ for driver in cc gcc c89 c99 ; do
+ if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD=$driver
+ break
+ fi
+ done
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+ esac
+}
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if test -f /.attbin/uname ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case $UNAME_SYSTEM in
+Linux|GNU|GNU/*)
+ LIBC=unknown
+
+ set_cc_for_build
+ cat <<-EOF > "$dummy.c"
+ #if defined(__ANDROID__)
+ LIBC=android
+ #else
+ #include
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #elif defined(__GLIBC__)
+ LIBC=gnu
+ #else
+ #include
+ /* First heuristic to detect musl libc. */
+ #ifdef __DEFINED_va_list
+ LIBC=musl
+ #endif
+ #endif
+ #endif
+ EOF
+ cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ eval "$cc_set_libc"
+
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
+ fi
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+ echo unknown)`
+ case $UNAME_MACHINE_ARCH in
+ aarch64eb) machine=aarch64_be-unknown ;;
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
+ ;;
+ *) machine=$UNAME_MACHINE_ARCH-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case $UNAME_MACHINE_ARCH in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case $UNAME_MACHINE_ARCH in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case $UNAME_VERSION in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ GUESS=$machine-${os}${release}${abi-}
+ ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+ ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+ ;;
+ *:SecBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+ ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+ ;;
+ *:MidnightBSD:*:*)
+ GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+ ;;
+ *:ekkoBSD:*:*)
+ GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+ ;;
+ *:SolidBSD:*:*)
+ GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+ ;;
+ *:OS108:*:*)
+ GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+ ;;
+ macppc:MirBSD:*:*)
+ GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+ ;;
+ *:MirBSD:*:*)
+ GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+ ;;
+ *:Sortix:*:*)
+ GUESS=$UNAME_MACHINE-unknown-sortix
+ ;;
+ *:Twizzler:*:*)
+ GUESS=$UNAME_MACHINE-unknown-twizzler
+ ;;
+ *:Redox:*:*)
+ GUESS=$UNAME_MACHINE-unknown-redox
+ ;;
+ mips:OSF1:*.*)
+ GUESS=mips-dec-osf1
+ ;;
+ alpha:OSF1:*:*)
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ trap '' 0
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case $ALPHA_CPU_TYPE in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+ ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ GUESS=m68k-unknown-sysv4
+ ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ GUESS=$UNAME_MACHINE-unknown-amigaos
+ ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ GUESS=$UNAME_MACHINE-unknown-morphos
+ ;;
+ *:OS/390:*:*)
+ GUESS=i370-ibm-openedition
+ ;;
+ *:z/VM:*:*)
+ GUESS=s390-ibm-zvmoe
+ ;;
+ *:OS400:*:*)
+ GUESS=powerpc-ibm-os400
+ ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ GUESS=arm-acorn-riscix$UNAME_RELEASE
+ ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ GUESS=arm-unknown-riscos
+ ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ GUESS=hppa1.1-hitachi-hiuxmpp
+ ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ case `(/bin/universe) 2>/dev/null` in
+ att) GUESS=pyramid-pyramid-sysv3 ;;
+ *) GUESS=pyramid-pyramid-bsd ;;
+ esac
+ ;;
+ NILE*:*:*:dcosx)
+ GUESS=pyramid-pyramid-svr4
+ ;;
+ DRS?6000:unix:4.0:6*)
+ GUESS=sparc-icl-nx6
+ ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) GUESS=sparc-icl-nx7 ;;
+ esac
+ ;;
+ s390x:SunOS:*:*)
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+ ;;
+ sun4H:SunOS:5.*:*)
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-hal-solaris2$SUN_REL
+ ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris2$SUN_REL
+ ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ GUESS=i386-pc-auroraux$UNAME_RELEASE
+ ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ set_cc_for_build
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+ ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris3$SUN_REL
+ ;;
+ sun4*:SunOS:*:*)
+ case `/usr/bin/arch -k` in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like '4.1.3-JL'.
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+ GUESS=sparc-sun-sunos$SUN_REL
+ ;;
+ sun3*:SunOS:*:*)
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
+ ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+ case `/bin/arch` in
+ sun3)
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
+ ;;
+ sun4)
+ GUESS=sparc-sun-sunos$UNAME_RELEASE
+ ;;
+ esac
+ ;;
+ aushp:SunOS:*:*)
+ GUESS=sparc-auspex-sunos$UNAME_RELEASE
+ ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ GUESS=m68k-milan-mint$UNAME_RELEASE
+ ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ GUESS=m68k-hades-mint$UNAME_RELEASE
+ ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ GUESS=m68k-unknown-mint$UNAME_RELEASE
+ ;;
+ m68k:machten:*:*)
+ GUESS=m68k-apple-machten$UNAME_RELEASE
+ ;;
+ powerpc:machten:*:*)
+ GUESS=powerpc-apple-machten$UNAME_RELEASE
+ ;;
+ RISC*:Mach:*:*)
+ GUESS=mips-dec-mach_bsd4.3
+ ;;
+ RISC*:ULTRIX:*:*)
+ GUESS=mips-dec-ultrix$UNAME_RELEASE
+ ;;
+ VAX*:ULTRIX*:*:*)
+ GUESS=vax-dec-ultrix$UNAME_RELEASE
+ ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ GUESS=clipper-intergraph-clix$UNAME_RELEASE
+ ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ GUESS=mips-mips-riscos$UNAME_RELEASE
+ ;;
+ Motorola:PowerMAX_OS:*:*)
+ GUESS=powerpc-motorola-powermax
+ ;;
+ Motorola:*:4.3:PL8-*)
+ GUESS=powerpc-harris-powermax
+ ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ GUESS=powerpc-harris-powermax
+ ;;
+ Night_Hawk:Power_UNIX:*:*)
+ GUESS=powerpc-harris-powerunix
+ ;;
+ m88k:CX/UX:7*:*)
+ GUESS=m88k-harris-cxux7
+ ;;
+ m88k:*:4*:R4*)
+ GUESS=m88k-motorola-sysv4
+ ;;
+ m88k:*:3*:R3*)
+ GUESS=m88k-motorola-sysv3
+ ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
+ then
+ if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+ test "$TARGET_BINARY_INTERFACE"x = x
+ then
+ GUESS=m88k-dg-dgux$UNAME_RELEASE
+ else
+ GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
+ fi
+ else
+ GUESS=i586-dg-dgux$UNAME_RELEASE
+ fi
+ ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ GUESS=m88k-dolphin-sysv3
+ ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ GUESS=m88k-motorola-sysv3
+ ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ GUESS=m88k-tektronix-sysv3
+ ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ GUESS=m68k-tektronix-bsd
+ ;;
+ *:IRIX*:*:*)
+ IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+ GUESS=mips-sgi-irix$IRIX_REL
+ ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ GUESS=i386-ibm-aix
+ ;;
+ ia64:AIX:*:*)
+ if test -x /usr/bin/oslevel ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
+ fi
+ GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+ ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ then
+ GUESS=$SYSTEM_NAME
+ else
+ GUESS=rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ GUESS=rs6000-ibm-aix3.2.4
+ else
+ GUESS=rs6000-ibm-aix3.2
+ fi
+ ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if test -x /usr/bin/lslpp ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
+ fi
+ GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+ ;;
+ *:AIX:*:*)
+ GUESS=rs6000-ibm-aix
+ ;;
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+ GUESS=romp-ibm-bsd4.4
+ ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to
+ ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ GUESS=rs6000-bull-bosx
+ ;;
+ DPX/2?00:B.O.S.:*:*)
+ GUESS=m68k-bull-sysv3
+ ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ GUESS=m68k-hp-bsd
+ ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ GUESS=m68k-hp-bsd4.4
+ ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ case $UNAME_MACHINE in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if test -x /usr/bin/getconf; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case $sc_cpu_version in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case $sc_kernel_bits in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if test "$HP_ARCH" = ""; then
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+
+ #define _HPUX_SOURCE
+ #include
+ #include
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if test "$HP_ARCH" = hppa2.0w
+ then
+ set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+ ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ GUESS=ia64-hp-hpux$HPUX_REV
+ ;;
+ 3050*:HI-UX:*:*)
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ GUESS=unknown-hitachi-hiuxwe2
+ ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+ GUESS=hppa1.1-hp-bsd
+ ;;
+ 9000/8??:4.3bsd:*:*)
+ GUESS=hppa1.0-hp-bsd
+ ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ GUESS=hppa1.0-hp-mpeix
+ ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+ GUESS=hppa1.1-hp-osf
+ ;;
+ hp8??:OSF1:*:*)
+ GUESS=hppa1.0-hp-osf
+ ;;
+ i*86:OSF1:*:*)
+ if test -x /usr/sbin/sysversion ; then
+ GUESS=$UNAME_MACHINE-unknown-osf1mk
+ else
+ GUESS=$UNAME_MACHINE-unknown-osf1
+ fi
+ ;;
+ parisc*:Lites*:*:*)
+ GUESS=hppa1.1-hp-lites
+ ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ GUESS=c1-convex-bsd
+ ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ GUESS=c34-convex-bsd
+ ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ GUESS=c38-convex-bsd
+ ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ GUESS=c4-convex-bsd
+ ;;
+ CRAY*Y-MP:*:*:*)
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=ymp-cray-unicos$CRAY_REL
+ ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=t90-cray-unicos$CRAY_REL
+ ;;
+ CRAY*T3E:*:*:*)
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=alphaev5-cray-unicosmk$CRAY_REL
+ ;;
+ CRAY*SV1:*:*:*)
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=sv1-cray-unicos$CRAY_REL
+ ;;
+ *:UNICOS/mp:*:*)
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=craynv-cray-unicosmp$CRAY_REL
+ ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+ ;;
+ sparc*:BSD/OS:*:*)
+ GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+ ;;
+ *:BSD/OS:*:*)
+ GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+ ;;
+ arm:FreeBSD:*:*)
+ UNAME_PROCESSOR=`uname -p`
+ set_cc_for_build
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
+ else
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
+ fi
+ ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`uname -p`
+ case $UNAME_PROCESSOR in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+ ;;
+ i*:CYGWIN*:*)
+ GUESS=$UNAME_MACHINE-pc-cygwin
+ ;;
+ *:MINGW64*:*)
+ GUESS=$UNAME_MACHINE-pc-mingw64
+ ;;
+ *:MINGW*:*)
+ GUESS=$UNAME_MACHINE-pc-mingw32
+ ;;
+ *:MSYS*:*)
+ GUESS=$UNAME_MACHINE-pc-msys
+ ;;
+ i*:PW*:*)
+ GUESS=$UNAME_MACHINE-pc-pw32
+ ;;
+ *:SerenityOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-serenity
+ ;;
+ *:Interix*:*)
+ case $UNAME_MACHINE in
+ x86)
+ GUESS=i586-pc-interix$UNAME_RELEASE
+ ;;
+ authenticamd | genuineintel | EM64T)
+ GUESS=x86_64-unknown-interix$UNAME_RELEASE
+ ;;
+ IA64)
+ GUESS=ia64-unknown-interix$UNAME_RELEASE
+ ;;
+ esac ;;
+ i*:UWIN*:*)
+ GUESS=$UNAME_MACHINE-pc-uwin
+ ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ GUESS=x86_64-pc-cygwin
+ ;;
+ prep*:SunOS:5.*:*)
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=powerpcle-unknown-solaris2$SUN_REL
+ ;;
+ *:GNU:*:*)
+ # the GNU system
+ GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+ GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+ ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+ ;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
+ *:Minix:*:*)
+ GUESS=$UNAME_MACHINE-unknown-minix
+ ;;
+ aarch64:Linux:*:*)
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __ARM_EABI__
+ #ifdef __ARM_PCS_VFP
+ ABI=eabihf
+ #else
+ ABI=eabi
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+ esac
+ fi
+ GUESS=$CPU-unknown-linux-$LIBCABI
+ ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ arm*:Linux:*:*)
+ set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
+ else
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ ;;
+ avr32*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ cris:Linux:*:*)
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
+ crisv32:Linux:*:*)
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
+ e2k:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ frv:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ hexagon:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ i*86:Linux:*:*)
+ GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+ ;;
+ ia64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ k1om:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:cos:*:*)
+ GUESS=$UNAME_MACHINE-unknown-cos
+ ;;
+ kvx:mbr:*:*)
+ GUESS=$UNAME_MACHINE-unknown-mbr
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ m32r*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ m68*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ set_cc_for_build
+ IS_GLIBC=0
+ test x"${LIBC}" = xgnu && IS_GLIBC=1
+ sed 's/^ //' << EOF > "$dummy.c"
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #undef mips64
+ #undef mips64el
+ #if ${IS_GLIBC} && defined(_ABI64)
+ LIBCABI=gnuabi64
+ #else
+ #if ${IS_GLIBC} && defined(_ABIN32)
+ LIBCABI=gnuabin32
+ #else
+ LIBCABI=${LIBC}
+ #endif
+ #endif
+
+ #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa64r6
+ #else
+ #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa32r6
+ #else
+ #if defined(__mips64)
+ CPU=mips64
+ #else
+ CPU=mips
+ #endif
+ #endif
+ #endif
+
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ MIPS_ENDIAN=el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ MIPS_ENDIAN=
+ #else
+ MIPS_ENDIAN=
+ #endif
+ #endif
+EOF
+ cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+ eval "$cc_set_vars"
+ test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ openrisc*:Linux:*:*)
+ GUESS=or1k-unknown-linux-$LIBC
+ ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ padre:Linux:*:*)
+ GUESS=sparc-unknown-linux-$LIBC
+ ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ GUESS=hppa64-unknown-linux-$LIBC
+ ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+ PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+ *) GUESS=hppa-unknown-linux-$LIBC ;;
+ esac
+ ;;
+ ppc64:Linux:*:*)
+ GUESS=powerpc64-unknown-linux-$LIBC
+ ;;
+ ppc:Linux:*:*)
+ GUESS=powerpc-unknown-linux-$LIBC
+ ;;
+ ppc64le:Linux:*:*)
+ GUESS=powerpc64le-unknown-linux-$LIBC
+ ;;
+ ppcle:Linux:*:*)
+ GUESS=powerpcle-unknown-linux-$LIBC
+ ;;
+ riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+ ;;
+ sh64*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ sh*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ tile*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ vax:Linux:*:*)
+ GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+ ;;
+ x86_64:Linux:*:*)
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __i386__
+ ABI=x86
+ #else
+ #ifdef __ILP32__
+ ABI=x32
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ x86) CPU=i686 ;;
+ x32) LIBCABI=${LIBC}x32 ;;
+ esac
+ fi
+ GUESS=$CPU-pc-linux-$LIBCABI
+ ;;
+ xtensa*:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ GUESS=i386-sequent-sysv4
+ ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+ ;;
+ i*86:OS/2:*:*)
+ # If we were able to find 'uname', then EMX Unix compatibility
+ # is probably installed.
+ GUESS=$UNAME_MACHINE-pc-os2-emx
+ ;;
+ i*86:XTS-300:*:STOP)
+ GUESS=$UNAME_MACHINE-unknown-stop
+ ;;
+ i*86:atheos:*:*)
+ GUESS=$UNAME_MACHINE-unknown-atheos
+ ;;
+ i*86:syllable:*:*)
+ GUESS=$UNAME_MACHINE-pc-syllable
+ ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ GUESS=i386-unknown-lynxos$UNAME_RELEASE
+ ;;
+ i*86:*DOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+ ;;
+ i*86:*:4.*:*)
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
+ else
+ GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
+ fi
+ ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
+ else
+ GUESS=$UNAME_MACHINE-pc-sysv32
+ fi
+ ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ GUESS=i586-pc-msdosdjgpp
+ ;;
+ Intel:Mach:3*:*)
+ GUESS=i386-pc-mach3
+ ;;
+ paragon:*:*:*)
+ GUESS=i860-intel-osf1
+ ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4
+ fi
+ ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ GUESS=m68010-convergent-sysv
+ ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ GUESS=m68k-convergent-sysv
+ ;;
+ M680?0:D-NIX:5.3:*)
+ GUESS=m68k-diab-dnix
+ ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+ ;;
+ mc68030:UNIX_System_V:4.*:*)
+ GUESS=m68k-atari-sysv4
+ ;;
+ TSUNAMI:LynxOS:2.*:*)
+ GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+ ;;
+ rs6000:LynxOS:2.*:*)
+ GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+ ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+ ;;
+ SM[BE]S:UNIX_SV:*:*)
+ GUESS=mips-dde-sysv$UNAME_RELEASE
+ ;;
+ RM*:ReliantUNIX-*:*:*)
+ GUESS=mips-sni-sysv4
+ ;;
+ RM*:SINIX-*:*:*)
+ GUESS=mips-sni-sysv4
+ ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ GUESS=$UNAME_MACHINE-sni-sysv4
+ else
+ GUESS=ns32k-sni-sysv
+ fi
+ ;;
+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
+ # says
+ GUESS=i586-unisys-sysv4
+ ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes .
+ # How about differentiating between stratus architectures? -djm
+ GUESS=hppa1.1-stratus-sysv4
+ ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ GUESS=i860-stratus-sysv4
+ ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ GUESS=$UNAME_MACHINE-stratus-vos
+ ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ GUESS=hppa1.1-stratus-vos
+ ;;
+ mc68*:A/UX:*:*)
+ GUESS=m68k-apple-aux$UNAME_RELEASE
+ ;;
+ news*:NEWS-OS:6*:*)
+ GUESS=mips-sony-newsos6
+ ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if test -d /usr/nec; then
+ GUESS=mips-nec-sysv$UNAME_RELEASE
+ else
+ GUESS=mips-unknown-sysv$UNAME_RELEASE
+ fi
+ ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ GUESS=powerpc-be-beos
+ ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ GUESS=powerpc-apple-beos
+ ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ GUESS=i586-pc-beos
+ ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ GUESS=i586-pc-haiku
+ ;;
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
+ GUESS=powerpc-apple-haiku
+ ;;
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
+ GUESS=$UNAME_MACHINE-unknown-haiku
+ ;;
+ SX-4:SUPER-UX:*:*)
+ GUESS=sx4-nec-superux$UNAME_RELEASE
+ ;;
+ SX-5:SUPER-UX:*:*)
+ GUESS=sx5-nec-superux$UNAME_RELEASE
+ ;;
+ SX-6:SUPER-UX:*:*)
+ GUESS=sx6-nec-superux$UNAME_RELEASE
+ ;;
+ SX-7:SUPER-UX:*:*)
+ GUESS=sx7-nec-superux$UNAME_RELEASE
+ ;;
+ SX-8:SUPER-UX:*:*)
+ GUESS=sx8-nec-superux$UNAME_RELEASE
+ ;;
+ SX-8R:SUPER-UX:*:*)
+ GUESS=sx8r-nec-superux$UNAME_RELEASE
+ ;;
+ SX-ACE:SUPER-UX:*:*)
+ GUESS=sxace-nec-superux$UNAME_RELEASE
+ ;;
+ Power*:Rhapsody:*:*)
+ GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+ ;;
+ *:Rhapsody:*:*)
+ GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+ ;;
+ arm64:Darwin:*:*)
+ GUESS=aarch64-apple-darwin$UNAME_RELEASE
+ ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p`
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ if command -v xcode-select > /dev/null 2> /dev/null && \
+ ! xcode-select --print-path > /dev/null 2> /dev/null ; then
+ # Avoid executing cc if there is no toolchain installed as
+ # cc will be a stub that puts up a graphical alert
+ # prompting the user to install developer tools.
+ CC_FOR_BUILD=no_compiler_found
+ else
+ set_cc_for_build
+ fi
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # uname -m returns i386 or x86_64
+ UNAME_PROCESSOR=$UNAME_MACHINE
+ fi
+ GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+ ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+ ;;
+ *:QNX:*:4*)
+ GUESS=i386-pc-qnx
+ ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ GUESS=neo-tandem-nsk$UNAME_RELEASE
+ ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ GUESS=nse-tandem-nsk$UNAME_RELEASE
+ ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ GUESS=nsr-tandem-nsk$UNAME_RELEASE
+ ;;
+ NSV-*:NONSTOP_KERNEL:*:*)
+ GUESS=nsv-tandem-nsk$UNAME_RELEASE
+ ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ GUESS=nsx-tandem-nsk$UNAME_RELEASE
+ ;;
+ *:NonStop-UX:*:*)
+ GUESS=mips-compaq-nonstopux
+ ;;
+ BS2000:POSIX*:*:*)
+ GUESS=bs2000-siemens-sysv
+ ;;
+ DS/*:UNIX_System_V:*:*)
+ GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+ ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "${cputype-}" = 386; then
+ UNAME_MACHINE=i386
+ elif test "x${cputype-}" != x; then
+ UNAME_MACHINE=$cputype
+ fi
+ GUESS=$UNAME_MACHINE-unknown-plan9
+ ;;
+ *:TOPS-10:*:*)
+ GUESS=pdp10-unknown-tops10
+ ;;
+ *:TENEX:*:*)
+ GUESS=pdp10-unknown-tenex
+ ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ GUESS=pdp10-dec-tops20
+ ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ GUESS=pdp10-xkl-tops20
+ ;;
+ *:TOPS-20:*:*)
+ GUESS=pdp10-unknown-tops20
+ ;;
+ *:ITS:*:*)
+ GUESS=pdp10-unknown-its
+ ;;
+ SEI:*:*:SEIUX)
+ GUESS=mips-sei-seiux$UNAME_RELEASE
+ ;;
+ *:DragonFly:*:*)
+ DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+ ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case $UNAME_MACHINE in
+ A*) GUESS=alpha-dec-vms ;;
+ I*) GUESS=ia64-dec-vms ;;
+ V*) GUESS=vax-dec-vms ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ GUESS=i386-pc-xenix
+ ;;
+ i*86:skyos:*:*)
+ SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+ GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+ ;;
+ i*86:rdos:*:*)
+ GUESS=$UNAME_MACHINE-pc-rdos
+ ;;
+ i*86:Fiwix:*:*)
+ GUESS=$UNAME_MACHINE-pc-fiwix
+ ;;
+ *:AROS:*:*)
+ GUESS=$UNAME_MACHINE-unknown-aros
+ ;;
+ x86_64:VMkernel:*:*)
+ GUESS=$UNAME_MACHINE-unknown-esx
+ ;;
+ amd64:Isilon\ OneFS:*:*)
+ GUESS=x86_64-unknown-onefs
+ ;;
+ *:Unleashed:*:*)
+ GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+ ;;
+esac
+
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+ echo "$GUESS"
+ exit
+fi
+
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <
+#include
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include
+#if defined (BSD)
+#if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname un;
+ uname (&un);
+ printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname *un;
+ uname (&un);
+ printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
+echo "$0: unable to guess system type" >&2
+
+case $UNAME_MACHINE:$UNAME_SYSTEM in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <&2 <&2 </dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+fi
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
ADDED build-aux/config.sub
Index: build-aux/config.sub
==================================================================
--- /dev/null
+++ build-aux/config.sub
@@ -0,0 +1,1960 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2023 Free Software Foundation, Inc.
+
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-09-19'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see .
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to .
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2023 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try '$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo "$1"
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Split fields of configuration type
+# shellcheck disable=SC2162
+saved_IFS=$IFS
+IFS="-" read field1 field2 field3 field4 <&2
+ exit 1
+ ;;
+ *-*-*-*)
+ basic_machine=$field1-$field2
+ basic_os=$field3-$field4
+ ;;
+ *-*-*)
+ # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+ # parts
+ maybe_os=$field2-$field3
+ case $maybe_os in
+ nto-qnx* | linux-* | uclinux-uclibc* \
+ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
+ | windows-* )
+ basic_machine=$field1
+ basic_os=$maybe_os
+ ;;
+ android-linux)
+ basic_machine=$field1-unknown
+ basic_os=linux-android
+ ;;
+ *)
+ basic_machine=$field1-$field2
+ basic_os=$field3
+ ;;
+ esac
+ ;;
+ *-*)
+ # A lone config we happen to match not fitting any pattern
+ case $field1-$field2 in
+ decstation-3100)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ *-*)
+ # Second component is usually, but not always the OS
+ case $field2 in
+ # Prevent following clause from handling this valid os
+ sun*os*)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
+ # Manufacturers
+ dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+ | unicom* | ibm* | next | hp | isi* | apollo | altos* \
+ | convergent* | ncr* | news | 32* | 3600* | 3100* \
+ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+ | ultra | tti* | harris | dolphin | highlevel | gould \
+ | cbm | ns | masscomp | apple | axis | knuth | cray \
+ | microblaze* | sim | cisco \
+ | oki | wec | wrs | winbond)
+ basic_machine=$field1-$field2
+ basic_os=
+ ;;
+ *)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ *)
+ # Convert single-component short-hands not valid as part of
+ # multi-component configurations.
+ case $field1 in
+ 386bsd)
+ basic_machine=i386-pc
+ basic_os=bsd
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ basic_os=scout
+ ;;
+ alliant)
+ basic_machine=fx80-alliant
+ basic_os=
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ basic_os=
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ basic_os=bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ basic_os=sysv
+ ;;
+ amiga)
+ basic_machine=m68k-unknown
+ basic_os=
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ basic_os=amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ basic_os=sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ basic_os=sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ basic_os=bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ basic_os=aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ basic_os=aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ basic_os=dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ basic_os=linux
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ basic_os=cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ basic_os=bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ basic_os=bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ basic_os=bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ basic_os=bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ basic_os=bsd
+ ;;
+ cray)
+ basic_machine=j90-cray
+ basic_os=unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ basic_os=
+ ;;
+ da30)
+ basic_machine=m68k-da30
+ basic_os=
+ ;;
+ decstation | pmax | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ basic_os=sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ basic_os=dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ basic_os=msdosdjgpp
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ basic_os=ebmon
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ basic_os=ose
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ basic_os=sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ basic_os=go32
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ basic_os=hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ basic_os=xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ basic_os=hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ basic_os=sysv3
+ ;;
+ hp300 | hp300hpux)
+ basic_machine=m68k-hp
+ basic_os=hpux
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ basic_os=bsd
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ basic_os=osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ basic_os=proelf
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ basic_os=mach
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ basic_os=sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ basic_os=linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ basic_os=sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ basic_os=sysv
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ basic_os=mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ basic_os=mingw32ce
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ basic_os=morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ basic_os=moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ basic_os=msdos
+ ;;
+ msys)
+ basic_machine=i686-pc
+ basic_os=msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ basic_os=mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ basic_os=nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ basic_os=sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-pc
+ basic_os=netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ basic_os=linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ basic_os=newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ basic_os=newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ basic_os=sysv
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ basic_os=cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ basic_os=cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ basic_os=nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ basic_os=mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ basic_os=nonstopux
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ basic_os=os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ basic_os=ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ basic_os=os68k
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ basic_os=osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ basic_os=linux
+ ;;
+ psp)
+ basic_machine=mipsallegrexel-sony
+ basic_os=psp
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ basic_os=pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ basic_os=rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ basic_os=rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ sei)
+ basic_machine=mips-sei
+ basic_os=seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ basic_os=
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ basic_os=sysv2
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ basic_os=
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ basic_os=sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ basic_os=
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ basic_os=sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ basic_os=sunos4
+ ;;
+ sun3)
+ basic_machine=m68k-sun
+ basic_os=
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ basic_os=sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ basic_os=sunos4
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ basic_os=
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ basic_os=sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ basic_os=sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ basic_os=solaris2
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ basic_os=
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ basic_os=unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ basic_os=dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ basic_os=unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ basic_os=unicos
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ basic_os=tops20
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ basic_os=tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ basic_os=sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ basic_os=none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ basic_os=sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ basic_os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ basic_os=vsta
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ basic_os=vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ basic_os=vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ basic_os=vxworks
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ basic_os=unicos
+ ;;
+ *)
+ basic_machine=$1
+ basic_os=
+ ;;
+ esac
+ ;;
+esac
+
+# Decode 1-component or ad-hoc basic machines
+case $basic_machine in
+ # Here we handle the default manufacturer of certain CPU types. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ cpu=hppa1.1
+ vendor=winbond
+ ;;
+ op50n)
+ cpu=hppa1.1
+ vendor=oki
+ ;;
+ op60c)
+ cpu=hppa1.1
+ vendor=oki
+ ;;
+ ibm*)
+ cpu=i370
+ vendor=ibm
+ ;;
+ orion105)
+ cpu=clipper
+ vendor=highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ cpu=m68k
+ vendor=apple
+ ;;
+ pmac | pmac-mpw)
+ cpu=powerpc
+ vendor=apple
+ ;;
+
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ cpu=m68000
+ vendor=att
+ ;;
+ 3b*)
+ cpu=we32k
+ vendor=att
+ ;;
+ bluegene*)
+ cpu=powerpc
+ vendor=ibm
+ basic_os=cnk
+ ;;
+ decsystem10* | dec10*)
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops10
+ ;;
+ decsystem20* | dec20*)
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ cpu=m68k
+ vendor=motorola
+ ;;
+ dpx2*)
+ cpu=m68k
+ vendor=bull
+ basic_os=sysv3
+ ;;
+ encore | umax | mmax)
+ cpu=ns32k
+ vendor=encore
+ ;;
+ elxsi)
+ cpu=elxsi
+ vendor=elxsi
+ basic_os=${basic_os:-bsd}
+ ;;
+ fx2800)
+ cpu=i860
+ vendor=alliant
+ ;;
+ genix)
+ cpu=ns32k
+ vendor=ns
+ ;;
+ h3050r* | hiux*)
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ cpu=m68000
+ vendor=hp
+ ;;
+ hp9k3[2-9][0-9])
+ cpu=m68k
+ vendor=hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ cpu=hppa1.1
+ vendor=hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ cpu=hppa1.0
+ vendor=hp
+ ;;
+ i*86v32)
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv32
+ ;;
+ i*86v4*)
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv4
+ ;;
+ i*86v)
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv
+ ;;
+ i*86sol2)
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=solaris2
+ ;;
+ j90 | j90-cray)
+ cpu=j90
+ vendor=cray
+ basic_os=${basic_os:-unicos}
+ ;;
+ iris | iris4d)
+ cpu=mips
+ vendor=sgi
+ case $basic_os in
+ irix*)
+ ;;
+ *)
+ basic_os=irix4
+ ;;
+ esac
+ ;;
+ miniframe)
+ cpu=m68000
+ vendor=convergent
+ ;;
+ *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ cpu=m68k
+ vendor=atari
+ basic_os=mint
+ ;;
+ news-3600 | risc-news)
+ cpu=mips
+ vendor=sony
+ basic_os=newsos
+ ;;
+ next | m*-next)
+ cpu=m68k
+ vendor=next
+ case $basic_os in
+ openstep*)
+ ;;
+ nextstep*)
+ ;;
+ ns2*)
+ basic_os=nextstep2
+ ;;
+ *)
+ basic_os=nextstep3
+ ;;
+ esac
+ ;;
+ np1)
+ cpu=np1
+ vendor=gould
+ ;;
+ op50n-* | op60c-*)
+ cpu=hppa1.1
+ vendor=oki
+ basic_os=proelf
+ ;;
+ pa-hitachi)
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
+ ;;
+ pbd)
+ cpu=sparc
+ vendor=tti
+ ;;
+ pbb)
+ cpu=m68k
+ vendor=tti
+ ;;
+ pc532)
+ cpu=ns32k
+ vendor=pc532
+ ;;
+ pn)
+ cpu=pn
+ vendor=gould
+ ;;
+ power)
+ cpu=power
+ vendor=ibm
+ ;;
+ ps2)
+ cpu=i386
+ vendor=ibm
+ ;;
+ rm[46]00)
+ cpu=mips
+ vendor=siemens
+ ;;
+ rtpc | rtpc-*)
+ cpu=romp
+ vendor=ibm
+ ;;
+ sde)
+ cpu=mipsisa32
+ vendor=sde
+ basic_os=${basic_os:-elf}
+ ;;
+ simso-wrs)
+ cpu=sparclite
+ vendor=wrs
+ basic_os=vxworks
+ ;;
+ tower | tower-32)
+ cpu=m68k
+ vendor=ncr
+ ;;
+ vpp*|vx|vx-*)
+ cpu=f301
+ vendor=fujitsu
+ ;;
+ w65)
+ cpu=w65
+ vendor=wdc
+ ;;
+ w89k-*)
+ cpu=hppa1.1
+ vendor=winbond
+ basic_os=proelf
+ ;;
+ none)
+ cpu=none
+ vendor=none
+ ;;
+ leon|leon[3-9])
+ cpu=sparc
+ vendor=$basic_machine
+ ;;
+ leon-*|leon[3-9]-*)
+ cpu=sparc
+ vendor=`echo "$basic_machine" | sed 's/-.*//'`
+ ;;
+
+ *-*)
+ # shellcheck disable=SC2162
+ saved_IFS=$IFS
+ IFS="-" read cpu vendor <&2
+ exit 1
+ ;;
+ esac
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $vendor in
+ digital*)
+ vendor=dec
+ ;;
+ commodore*)
+ vendor=cbm
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if test x"$basic_os" != x
+then
+
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
+# set os.
+obj=
+case $basic_os in
+ gnu/linux*)
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
+ ;;
+ os2-emx)
+ kernel=os2
+ os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
+ ;;
+ nto-qnx*)
+ kernel=nto
+ os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
+ ;;
+ *-*)
+ # shellcheck disable=SC2162
+ saved_IFS=$IFS
+ IFS="-" read kernel os <&2
+ fi
+ ;;
+ *)
+ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+case $obj in
+ aout* | coff* | elf* | pe*)
+ ;;
+ '')
+ # empty is fine
+ ;;
+ *)
+ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+ # The "javascript-unknown-ghcjs" triple is used by GHC; we
+ # accept it here in order to tolerate that, but reject any
+ # variations.
+ javascript-ghcjs)
+ ;;
+ javascript-* | *-ghcjs)
+ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
+ exit 1
+ ;;
+esac
+
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os-$obj in
+ linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \
+ | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- )
+ ;;
+ uclinux-uclibc*- )
+ ;;
+ managarm-mlibc*- | managarm-kernel*- )
+ ;;
+ windows*-msvc*-)
+ ;;
+ -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- )
+ # These are just libc implementations, not actual OSes, and thus
+ # require a kernel.
+ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ -kernel*- )
+ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ *-kernel*- )
+ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+ exit 1
+ ;;
+ *-msvc*- )
+ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+ exit 1
+ ;;
+ kfreebsd*-gnu*- | kopensolaris*-gnu*-)
+ ;;
+ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+ ;;
+ nto-qnx*-)
+ ;;
+ os2-emx-)
+ ;;
+ *-eabi*- | *-gnueabi*-)
+ ;;
+ none--*)
+ # None (no kernel, i.e. freestanding / bare metal),
+ # can be paired with an machine code file format
+ ;;
+ -*-)
+ # Blank kernel with real OS is always fine.
+ ;;
+ --*)
+ # Blank kernel and OS with real machine code file format is always fine.
+ ;;
+ *-*-*)
+ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+case $vendor in
+ unknown)
+ case $cpu-$os in
+ *-riscix*)
+ vendor=acorn
+ ;;
+ *-sunos*)
+ vendor=sun
+ ;;
+ *-cnk* | *-aix*)
+ vendor=ibm
+ ;;
+ *-beos*)
+ vendor=be
+ ;;
+ *-hpux*)
+ vendor=hp
+ ;;
+ *-mpeix*)
+ vendor=hp
+ ;;
+ *-hiux*)
+ vendor=hitachi
+ ;;
+ *-unos*)
+ vendor=crds
+ ;;
+ *-dgux*)
+ vendor=dg
+ ;;
+ *-luna*)
+ vendor=omron
+ ;;
+ *-genix*)
+ vendor=ns
+ ;;
+ *-clix*)
+ vendor=intergraph
+ ;;
+ *-mvs* | *-opened*)
+ vendor=ibm
+ ;;
+ *-os400*)
+ vendor=ibm
+ ;;
+ s390-* | s390x-*)
+ vendor=ibm
+ ;;
+ *-ptx*)
+ vendor=sequent
+ ;;
+ *-tpf*)
+ vendor=ibm
+ ;;
+ *-vxsim* | *-vxworks* | *-windiss*)
+ vendor=wrs
+ ;;
+ *-aux*)
+ vendor=apple
+ ;;
+ *-hms*)
+ vendor=hitachi
+ ;;
+ *-mpw* | *-macos*)
+ vendor=apple
+ ;;
+ *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
+ vendor=atari
+ ;;
+ *-vos*)
+ vendor=stratus
+ ;;
+ esac
+ ;;
+esac
+
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
+exit
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
ADDED build-aux/install-sh
Index: build-aux/install-sh
==================================================================
--- /dev/null
+++ build-aux/install-sh
@@ -0,0 +1,541 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2023-11-23.18; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+# Create dirs (including intermediate dirs) using mode 755.
+# This is like GNU 'install' as of coreutils 8.32 (2020).
+mkdir_umask=22
+
+backupsuffix=
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -p pass -p to $cpprog.
+ -s $stripprog installed files.
+ -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+If -S is not specified, no backups are attempted.
+
+Report bugs to .
+GNU Automake home page: .
+General help using GNU software: ."
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -p) cpprog="$cpprog -p";;
+
+ -s) stripcmd=$stripprog;;
+
+ -S) backupsuffix="$2"
+ shift;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ # Don't chown directories that already exist.
+ if test $dstdir_status = 0; then
+ chowncmd=""
+ fi
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ # The $RANDOM variable is not portable (e.g., dash). Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap '
+ ret=$?
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
+ exit $ret
+ ' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p'.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask &&
+ { test -z "$stripcmd" || {
+ # Create $dsttmp read-write so that cp doesn't create it read-only,
+ # which would cause strip to fail.
+ if test -z "$doit"; then
+ : >"$dsttmp" # No need to fork-exec 'touch'.
+ else
+ $doit touch "$dsttmp"
+ fi
+ }
+ } &&
+ $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # If $backupsuffix is set, and the file being installed
+ # already exists, attempt a backup. Don't worry if it fails,
+ # e.g., if mv doesn't support -f.
+ if test -n "$backupsuffix" && test -f "$dst"; then
+ $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+ fi
+
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
ADDED build-aux/m4/buildsys.m4
Index: build-aux/m4/buildsys.m4
==================================================================
--- /dev/null
+++ build-aux/m4/buildsys.m4
@@ -0,0 +1,393 @@
+dnl
+dnl Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017,
+dnl 2018, 2020, 2021, 2022, 2023, 2024
+dnl Jonathan Schleifer
+dnl
+dnl https://fossil.nil.im/buildsys
+dnl
+dnl Permission to use, copy, modify, and/or distribute this software for any
+dnl purpose with or without fee is hereby granted, provided that the above
+dnl copyright notice and this permission notice is present in all copies.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+dnl AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+dnl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+dnl ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+dnl LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+dnl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+dnl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+dnl CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+dnl ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+dnl POSSIBILITY OF SUCH DAMAGE.
+dnl
+
+AC_DEFUN([BUILDSYS_INIT], [
+ AC_REQUIRE([AC_CANONICAL_BUILD])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+
+ AC_ARG_ENABLE(rpath,
+ AS_HELP_STRING([--disable-rpath], [do not use rpath]))
+
+ AC_ARG_ENABLE(silent-rules,
+ AS_HELP_STRING([--disable-silent-rules],
+ [print executed commands during build]))
+
+ case "$build_os" in
+ darwin*)
+ case "$host_os" in
+ darwin*)
+ AC_SUBST(BUILD_AND_HOST_ARE_DARWIN, yes)
+ ;;
+ esac
+ ;;
+ esac
+
+ AC_PROG_INSTALL
+ case "$INSTALL" in
+ ./build-aux/install-sh*)
+ INSTALL="$PWD/$INSTALL"
+ ;;
+ esac
+
+ AC_CONFIG_COMMANDS_PRE([
+ AS_IF([test x"$GCC" = x"yes"],
+ [AC_SUBST(DEP_CFLAGS, '-MD -MF $${out%.o}.dep')])
+ AS_IF([test x"$GXX" = x"yes"],
+ [AC_SUBST(DEP_CXXFLAGS, '-MD -MF $${out%.o}.dep')])
+ AS_IF([test x"$GOBJC" = x"yes"],
+ [AC_SUBST(DEP_OBJCFLAGS, '-MD -MF $${out%.o}.dep')])
+ AS_IF([test x"$GOBJCXX" = x"yes"],
+ [AC_SUBST(DEP_OBJCXXFLAGS, '-MD -MF $${out%.o}.dep')])
+
+ AC_SUBST(AMIGA_LIB_CFLAGS)
+ AC_SUBST(AMIGA_LIB_LDFLAGS)
+
+ case "$build_os" in
+ morphos*)
+ dnl Don't use tput on MorphOS: The colored output is
+ dnl quite unreadable and in some MorphOS versions the
+ dnl output from tput is not 8-bit safe, with awk (for
+ dnl AC_SUBST) failing as a result.
+ ;;
+ *)
+ AC_PATH_PROG(TPUT, tput)
+ ;;
+ esac
+
+ AS_IF([test x"$TPUT" != x""], [
+ if x=$($TPUT el 2>/dev/null); then
+ AC_SUBST(TERM_EL, "$x")
+ else
+ AC_SUBST(TERM_EL, "$($TPUT ce 2>/dev/null)")
+ fi
+
+ if x=$($TPUT sgr0 2>/dev/null); then
+ AC_SUBST(TERM_SGR0, "$x")
+ else
+ AC_SUBST(TERM_SGR0, "$($TPUT me 2>/dev/null)")
+ fi
+
+ if x=$($TPUT bold 2>/dev/null); then
+ AC_SUBST(TERM_BOLD, "$x")
+ else
+ AC_SUBST(TERM_BOLD, "$($TPUT md 2>/dev/null)")
+ fi
+
+ if x=$($TPUT setaf 1 2>/dev/null); then
+ AC_SUBST(TERM_SETAF1, "$x")
+ AC_SUBST(TERM_SETAF2,
+ "$($TPUT setaf 2 2>/dev/null)")
+ AC_SUBST(TERM_SETAF3,
+ "$($TPUT setaf 3 2>/dev/null)")
+ AC_SUBST(TERM_SETAF4,
+ "$($TPUT setaf 4 2>/dev/null)")
+ AC_SUBST(TERM_SETAF6,
+ "$($TPUT setaf 6 2>/dev/null)")
+ dnl OpenBSD seems to want 3 parameters for terminals
+ dnl ending in -256color, but the additional two
+ dnl parameters don't seem to do anything, so we set
+ dnl them to 0.
+ elif x=$($TPUT setaf 1 0 0 2>/dev/null); then
+ AC_SUBST(TERM_SETAF1, "$x")
+ AC_SUBST(TERM_SETAF2,
+ "$($TPUT setaf 2 0 0 2>/dev/null)")
+ AC_SUBST(TERM_SETAF3,
+ "$($TPUT setaf 3 0 0 2>/dev/null)")
+ AC_SUBST(TERM_SETAF4,
+ "$($TPUT setaf 4 0 0 2>/dev/null)")
+ AC_SUBST(TERM_SETAF6,
+ "$($TPUT setaf 6 0 0 2>/dev/null)")
+ else
+ AC_SUBST(TERM_SETAF1,
+ "$($TPUT AF 1 2>/dev/null)")
+ AC_SUBST(TERM_SETAF2,
+ "$($TPUT AF 2 2>/dev/null)")
+ AC_SUBST(TERM_SETAF3,
+ "$($TPUT AF 3 2>/dev/null)")
+ AC_SUBST(TERM_SETAF4,
+ "$($TPUT AF 4 2>/dev/null)")
+ AC_SUBST(TERM_SETAF6,
+ "$($TPUT AF 6 2>/dev/null)")
+ fi
+ ])
+
+ AS_IF([test x"$enable_silent_rules" != x"no"], [
+ AC_SUBST(SILENT, '.SILENT:')
+ AC_SUBST(MAKEFLAGS_SILENT, '-s')
+ ])
+ ])
+])
+
+AC_DEFUN([BUILDSYS_CHECK_IOS], [
+ case "$host_os" in
+ darwin*)
+ AC_MSG_CHECKING(whether host is iOS)
+ AC_EGREP_CPP(yes, [
+ #include
+
+ #if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
+ (defined(TARGET_OS_SIMULATOR) && \
+ TARGET_OS_SIMULATOR)
+ yes
+ #endif
+ ], [
+ host_is_ios="yes"
+ AC_SUBST(HOST_IS_IOS, yes)
+ ], [
+ host_is_ios="no"
+ ])
+ AC_MSG_RESULT($host_is_ios)
+ AC_CHECK_TOOL(CODESIGN, codesign)
+ ;;
+ esac
+])
+
+AC_DEFUN([BUILDSYS_PROG_IMPLIB], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_MSG_CHECKING(whether we need an implib)
+ case "$host_os" in
+ cygwin* | mingw*)
+ AC_MSG_RESULT(yes)
+ PROG_IMPLIB_NEEDED='yes'
+ PROG_IMPLIB_LDFLAGS='-Wl,--export-all-symbols,--out-implib,lib${PROG}.a'
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ PROG_IMPLIB_NEEDED='no'
+ PROG_IMPLIB_LDFLAGS=''
+ ;;
+ esac
+
+ AC_SUBST(PROG_IMPLIB_NEEDED)
+ AC_SUBST(PROG_IMPLIB_LDFLAGS)
+])
+
+AC_DEFUN([BUILDSYS_SHARED_LIB], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([BUILDSYS_CHECK_IOS])
+ AC_MSG_CHECKING(for shared library type)
+
+ case "$host" in
+ *-*-darwin*)
+ AC_MSG_RESULT(Darwin)
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}'
+ LIB_LDFLAGS_INSTALL_NAME='-Wl,-install_name,${libdir}/$${out%.dylib}.${LIB_MAJOR}.dylib'
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.dylib'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,-rpath,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$$i'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib'
+ CLEAN_LIB=''
+ ;;
+ *-*-mingw* | *-*-cygwin*)
+ AC_MSG_RESULT(MinGW / Cygwin)
+ LIB_CFLAGS=''
+ LIB_LDFLAGS='-shared -Wl,--export-all-symbols'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX=''
+ LIB_SUFFIX='${LIB_MAJOR}.dll'
+ LINK_LIB='&& rm -f lib$${out%${LIB_SUFFIX}}.dll.a && ${LN_S} $$out lib$${out%${LIB_SUFFIX}}.dll.a'
+ INSTALL_LIB='&& ${MKDIR_P} ${DESTDIR}${bindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/$$i && ${INSTALL} -m 755 lib$${i%${LIB_SUFFIX}}.dll.a ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${bindir}/$$i ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a'
+ CLEAN_LIB='${SHARED_LIB}.a ${SHARED_LIB_NOINST}.a'
+ ;;
+ *-*-openbsd* | *-*-mirbsd*)
+ AC_MSG_RESULT(OpenBSD)
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.so.${LIB_MAJOR}.${LIB_MINOR}'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,-rpath,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i'
+ CLEAN_LIB=''
+ ;;
+ *-*-solaris*)
+ AC_MSG_RESULT(Solaris)
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}.${LIB_MINOR}'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.so'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,-rpath,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR} && rm -f ${DESTDIR}${libdir}/$$i && ${LN_S} $$i.${LIB_MAJOR}.${LIB_MINOR} ${DESTDIR}${libdir}/$$i'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}'
+ CLEAN_LIB=''
+ ;;
+ *-*-android*)
+ AC_MSG_RESULT(Android)
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.so'
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} ${DESTDIR}${libdir}/$$i'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH}'
+ CLEAN_LIB=''
+ ;;
+ hppa*-*-hpux*)
+ AC_MSG_RESULT([HP-UX (PA-RISC)])
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared -Wl,+h,$$out'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.${LIB_MAJOR}'
+ LINK_LIB='&& rm -f $${out%%.*}.sl && ${LN_S} $$out $${out%%.*}.sl'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,+b,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.sl'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%%.*}.sl'
+ CLEAN_LIB=''
+ ;;
+ ia64*-*-hpux*)
+ AC_MSG_RESULT([HP-UX (Itanium)])
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared -Wl,+h,$$out'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.${LIB_MAJOR}'
+ LINK_LIB='&& rm -f $${out%%.*}.so && ${LN_S} $$out $${out%%.*}.so'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,+b,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.so'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%%.*}.so'
+ CLEAN_LIB=''
+ ;;
+ *)
+ AC_MSG_RESULT(ELF)
+ LIB_CFLAGS='-fPIC -DPIC'
+ LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}'
+ LIB_LDFLAGS_INSTALL_NAME=''
+ LIB_PREFIX='lib'
+ LIB_SUFFIX='.so'
+ AS_IF([test x"$enable_rpath" != x"no"], [
+ LDFLAGS_RPATH='-Wl,-rpath,${libdir}'
+ ])
+ INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH} ${DESTDIR}${libdir}/$$i'
+ UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.${LIB_PATCH}'
+ CLEAN_LIB=''
+ ;;
+ esac
+
+ AC_SUBST(LIB_CFLAGS)
+ AC_SUBST(LIB_LDFLAGS)
+ AC_SUBST(LIB_LDFLAGS_INSTALL_NAME)
+ AC_SUBST(LIB_PREFIX)
+ AC_SUBST(LIB_SUFFIX)
+ AC_SUBST(LINK_LIB)
+ AC_SUBST(LDFLAGS_RPATH)
+ AC_SUBST(INSTALL_LIB)
+ AC_SUBST(UNINSTALL_LIB)
+ AC_SUBST(CLEAN_LIB)
+])
+
+AC_DEFUN([BUILDSYS_FRAMEWORK], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([BUILDSYS_CHECK_IOS])
+ AC_REQUIRE([BUILDSYS_SHARED_LIB])
+
+ case "$host_os" in
+ darwin*)
+ FRAMEWORK_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}'
+ AS_IF([test x"$host_is_ios" = x"yes"], [
+ FRAMEWORK_LDFLAGS_INSTALL_NAME='-Wl,-install_name,@executable_path/Frameworks/$$out/$${out%.framework}'
+ ], [
+ FRAMEWORK_LDFLAGS_INSTALL_NAME='-Wl,-install_name,@executable_path/../Frameworks/$$out/$${out%.framework}'
+ ])
+
+ AC_SUBST(FRAMEWORK_LDFLAGS)
+ AC_SUBST(FRAMEWORK_LDFLAGS_INSTALL_NAME)
+ AC_SUBST(FRAMEWORK_LIBS)
+
+ $1
+ ;;
+ esac
+])
+
+AC_DEFUN([BUILDSYS_PLUGIN], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([BUILDSYS_CHECK_IOS])
+ AC_MSG_CHECKING(for plugin type)
+
+ case "$host" in
+ *-*-darwin*)
+ AC_MSG_RESULT(Darwin)
+ PLUGIN_CFLAGS='-fPIC -DPIC'
+ PLUGIN_LDFLAGS='-bundle'
+ PLUGIN_SUFFIX='.dylib'
+ ;;
+ *-*-mingw* | *-*-cygwin*)
+ AC_MSG_RESULT(MinGW / Cygwin)
+ PLUGIN_CFLAGS=''
+ PLUGIN_LDFLAGS='-shared -Wl,--export-all-symbols'
+ PLUGIN_SUFFIX='.dll'
+ ;;
+ hppa*-*-hpux*)
+ AC_MSG_RESULT([HP-UX (PA-RISC)])
+ PLUGIN_CFLAGS='-fPIC -DPIC'
+ PLUGIN_LDFLAGS='-shared'
+ PLUGIN_SUFFIX='.sl'
+ ;;
+ *)
+ AC_MSG_RESULT(ELF)
+ PLUGIN_CFLAGS='-fPIC -DPIC'
+ PLUGIN_LDFLAGS='-shared'
+ PLUGIN_SUFFIX='.so'
+ ;;
+ esac
+
+ AC_SUBST(PLUGIN_CFLAGS)
+ AC_SUBST(PLUGIN_LDFLAGS)
+ AC_SUBST(PLUGIN_SUFFIX)
+])
+
+AC_DEFUN([BUILDSYS_BUNDLE], [
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([BUILDSYS_CHECK_IOS])
+ AC_REQUIRE([BUILDSYS_PLUGIN])
+
+ case "$host_os" in
+ darwin*)
+ AS_IF([test x"$host_is_ios" = x"yes"], [
+ LINK_BUNDLE='${MKDIR_P} $$out && ${INSTALL} -m 644 Info.plist $$out/Info.plist && ${LD} -o $$out/$${out%.bundle} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}'
+ ], [
+ LINK_BUNDLE='${MKDIR_P} $$out/Contents/MacOS && ${INSTALL} -m 644 Info.plist $$out/Contents/Info.plist && ${LD} -o $$out/Contents/MacOS/$${out%.bundle} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}'
+ ])
+
+ AC_SUBST(LINK_BUNDLE)
+
+ $1
+ ;;
+ esac
+])
ADDED build-aux/m4/pkg.m4
Index: build-aux/m4/pkg.m4
==================================================================
--- /dev/null
+++ build-aux/m4/pkg.m4
@@ -0,0 +1,343 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 11 (pkg-config-0.29.1)
+
+dnl Copyright © 2004 Scott James Remnant .
+dnl Copyright © 2012-2015 Dan Nicholson
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29.1])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+ [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see .])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
+dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
+dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
+dnl [DESCRIPTION], [DEFAULT])
+dnl ------------------------------------------
+dnl
+dnl Prepare a "--with-" configure option using the lowercase
+dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
+dnl PKG_CHECK_MODULES in a single macro.
+AC_DEFUN([PKG_WITH_MODULES],
+[
+m4_pushdef([with_arg], m4_tolower([$1]))
+
+m4_pushdef([description],
+ [m4_default([$5], [build with ]with_arg[ support])])
+
+m4_pushdef([def_arg], [m4_default([$6], [auto])])
+m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
+m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
+
+m4_case(def_arg,
+ [yes],[m4_pushdef([with_without], [--without-]with_arg)],
+ [m4_pushdef([with_without],[--with-]with_arg)])
+
+AC_ARG_WITH(with_arg,
+ AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
+ [AS_TR_SH([with_]with_arg)=def_arg])
+
+AS_CASE([$AS_TR_SH([with_]with_arg)],
+ [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
+ [auto],[PKG_CHECK_MODULES([$1],[$2],
+ [m4_n([def_action_if_found]) $3],
+ [m4_n([def_action_if_not_found]) $4])])
+
+m4_popdef([with_arg])
+m4_popdef([description])
+m4_popdef([def_arg])
+
+])dnl PKG_WITH_MODULES
+
+dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
+dnl [DESCRIPTION], [DEFAULT])
+dnl -----------------------------------------------
+dnl
+dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
+dnl check._[VARIABLE-PREFIX] is exported as make variable.
+AC_DEFUN([PKG_HAVE_WITH_MODULES],
+[
+PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
+
+AM_CONDITIONAL([HAVE_][$1],
+ [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
+])dnl PKG_HAVE_WITH_MODULES
+
+dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
+dnl [DESCRIPTION], [DEFAULT])
+dnl ------------------------------------------------------
+dnl
+dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
+dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
+dnl and preprocessor variable.
+AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
+[
+PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
+
+AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
+ [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
+])dnl PKG_HAVE_DEFINE_WITH_MODULES
ADDED buildsys.mk.in
Index: buildsys.mk.in
==================================================================
--- /dev/null
+++ buildsys.mk.in
@@ -0,0 +1,1130 @@
+#
+# Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
+# 2017, 2018, 2020, 2021, 2022, 2023, 2024
+# Jonathan Schleifer
+#
+# https://fossil.nil.im/buildsys
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice is present in all copies.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+AS = @AS@
+CC = @CC@
+CXX = @CXX@
+CPP = @CPP@
+DC = @DC@
+ERLC = @ERLC@
+OBJC = @OBJC@
+OBJCXX = @OBJCXX@
+AR = @AR@
+LD = ${CC}
+RANLIB = @RANLIB@
+PYTHON = @PYTHON@
+ASFLAGS = @ASFLAGS@
+CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
+CPPFLAGS = @CPPFLAGS@
+DFLAGS = @DFLAGS@
+ERLCFLAGS = @ERLCFLAGS@
+OBJCFLAGS = @OBJCFLAGS@
+OBJCXXFLAGS = @OBJCXXFLAGS@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_RPATH = @LDFLAGS_RPATH@
+LIBS = @LIBS@
+PYTHON_FLAGS = @PYTHON_FLAGS@
+PROG_IMPLIB_NEEDED = @PROG_IMPLIB_NEEDED@
+PROG_IMPLIB_LDFLAGS = @PROG_IMPLIB_LDFLAGS@
+PROG_SUFFIX = @EXEEXT@
+LIB_CFLAGS = @LIB_CFLAGS@
+LIB_LDFLAGS = @LIB_LDFLAGS@
+LIB_LDFLAGS_INSTALL_NAME = @LIB_LDFLAGS_INSTALL_NAME@
+LIB_PREFIX = @LIB_PREFIX@
+LIB_SUFFIX = @LIB_SUFFIX@
+LINK_LIB = @LINK_LIB@
+AMIGA_LIB_CFLAGS = @AMIGA_LIB_CFLAGS@
+AMIGA_LIB_LDFLAGS = @AMIGA_LIB_LDFLAGS@
+PLUGIN_CFLAGS = @PLUGIN_CFLAGS@
+PLUGIN_LDFLAGS = @PLUGIN_LDFLAGS@
+PLUGIN_SUFFIX = @PLUGIN_SUFFIX@
+FRAMEWORK_LDFLAGS = @FRAMEWORK_LDFLAGS@
+FRAMEWORK_LDFLAGS_INSTALL_NAME = @FRAMEWORK_LDFLAGS_INSTALL_NAME@
+FRAMEWORK_LIBS = @FRAMEWORK_LIBS@
+CODESIGN = @CODESIGN@
+CODESIGN_IDENTITY ?= -
+CLEAN_LIB = @CLEAN_LIB@
+DEP_ASFLAGS = @DEP_ASFLAGS@
+DEP_CFLAGS = @DEP_CFLAGS@
+DEP_CXXFLAGS = @DEP_CXXFLAGS@
+DEP_OBJCFLAGS = @DEP_OBJCFLAGS@
+DEP_OBJCXXFLAGS = @DEP_OBJCXXFLAGS@
+LN_S = @LN_S@
+MKDIR_P = mkdir -p
+INSTALL = @INSTALL@
+SHELL = @SHELL@
+MSGFMT = @MSGFMT@
+JAVAC = @JAVAC@
+JAVACFLAGS = @JAVACFLAGS@
+JAR = @JAR@
+RC = @RC@
+BUILD_AND_HOST_ARE_DARWIN = @BUILD_AND_HOST_ARE_DARWIN@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+amigalibdir ?= ${prefix}/libs
+plugindir ?= ${libdir}/${PACKAGE_NAME}
+bundledir ?= ${prefix}/Library/PlugIns/${PACKAGE_NAME}
+datarootdir = @datarootdir@
+datadir = @datadir@
+includedir = @includedir@
+includesubdir ?= ${PACKAGE_NAME}
+INSTALL_INCLUDES ?= yes
+localedir = @localedir@
+localename ?= ${PACKAGE_NAME}
+mandir = @mandir@
+mansubdir ?= man1
+
+OBJS1 = ${SRCS:.c=.o}
+OBJS2 = ${OBJS1:.cc=.o}
+OBJS3 = ${OBJS2:.cxx=.o}
+OBJS4 = ${OBJS3:.d=.o}
+OBJS5 = ${OBJS4:.erl=.beam}
+OBJS6 = ${OBJS5:.java=.class}
+OBJS7 = ${OBJS6:.m=.o}
+OBJS8 = ${OBJS7:.mm=.o}
+OBJS9 = ${OBJS8:.py=.pyc}
+OBJS10 = ${OBJS9:.rc=.o}
+OBJS11 = ${OBJS10:.S=.o}
+OBJS += ${OBJS11:.xpm=.o}
+
+LIB_OBJS = ${OBJS:.o=.lib.o}
+AMIGA_LIB_OBJS = ${OBJS:.o=.amigalib.o}
+PLUGIN_OBJS = ${OBJS:.o=.plugin.o}
+
+DEPS = ${OBJS:.o=.dep} \
+ ${LIB_OBJS:.o=.dep} \
+ ${AMIGA_LIB_OBJS:.o=.dep} \
+ ${PLUGIN_OBJS:.o=.dep}
+
+MO_FILES = ${LOCALES:.po=.mo}
+
+@SILENT@
+.SUFFIXES:
+.SUFFIXES: .amigalib.o .beam .c .cc .class .cxx .d .erl .lib.o .java \
+ .mo .m .mm .o .plugin.o .po .py .pyc .rc .S .xpm
+.PHONY: all subdirs subdirs-after pre-depend depend install \
+ install-extra uninstall uninstall-extra clean distclean locales \
+ copy-headers-into-framework ${SUBDIRS} ${SUBDIRS_AFTER}
+
+all:
+ ${MAKE} @MAKEFLAGS_SILENT@ pre-all
+ ${MAKE} @MAKEFLAGS_SILENT@ subdirs
+ ${MAKE} @MAKEFLAGS_SILENT@ depend
+ ${MAKE} @MAKEFLAGS_SILENT@ \
+ ${STATIC_LIB} ${STATIC_LIB_NOINST} \
+ ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} \
+ ${STATIC_AMIGA_LIB}${STATIC_AMIGA_LIB_NOINST} \
+ ${SHARED_LIB} ${SHARED_LIB_NOINST} \
+ ${FRAMEWORK} ${FRAMEWORK_NOINST} \
+ ${AMIGA_LIB} ${AMIGA_LIB_NOINST} \
+ ${PLUGIN} ${PLUGIN_NOINST} \
+ ${BUNDLE} ${BUNDLE_NOINST} \
+ ${PROG} ${PROG_NOINST} \
+ ${JARFILE} locales
+ ${MAKE} @MAKEFLAGS_SILENT@ subdirs-after
+ ${MAKE} @MAKEFLAGS_SILENT@ post-all
+
+pre-all post-all:
+
+subdirs: ${SUBDIRS}
+subdirs-after: ${SUBDIRS_AFTER}
+
+${SUBDIRS} ${SUBDIRS_AFTER}:
+ for i in $@; do \
+ ${DIR_ENTER}; \
+ ${MAKE} @MAKEFLAGS_SILENT@ || exit $$?; \
+ ${DIR_LEAVE}; \
+ done
+
+depend: pre-depend
+ : >.deps
+ for i in "" ${DEPS}; do \
+ test x"$$i" = x"" && continue; \
+ echo "-include \$${.CURDIR}/$$i" >>.deps; \
+ done
+
+pre-depend:
+
+${PROG} ${PROG_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA}
+ ${LINK_STATUS}
+ out="$@"; \
+ if ${LD} -o $@ ${OBJS} ${OBJS_EXTRA} ${LDFLAGS} ${LIBS}; then \
+ ${LINK_OK}; \
+ else \
+ ${LINK_FAILED}; \
+ fi
+
+${JARFILE}: ${EXT_DEPS} ${JAR_MANIFEST} ${OBJS} ${OBJS_EXTRA}
+ ${LINK_STATUS}
+ if test x"${JAR_MANIFEST}" != x""; then \
+ if ${JAR} cfm ${JARFILE} ${JAR_MANIFEST} ${OBJS} \
+ ${OBJS_EXTRA}; then \
+ ${LINK_OK}; \
+ else \
+ ${LINK_FAILED}; \
+ fi \
+ else \
+ if ${JAR} cf ${JARFILE} ${OBJS} ${OBJS_EXTRA}; then \
+ ${LINK_OK}; \
+ else \
+ ${LINK_FAILED}; \
+ fi \
+ fi
+
+${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA}
+ ${LINK_STATUS}
+ out="$@"; \
+ if ${LD} -o $@ ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LIB_LDFLAGS} \
+ ${LIB_LDFLAGS_INSTALL_NAME} ${LDFLAGS} ${LIBS} ${LINK_LIB}; then \
+ ${LINK_OK}; \
+ else \
+ ${LINK_FAILED}; \
+ fi
+
+${FRAMEWORK} ${FRAMEWORK_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA}
+ ${LINK_STATUS}
+ out="$@"; \
+ if test x"@HOST_IS_IOS@" = x"yes"; then \
+ if rm -fr $@ && \
+ ${MAKE} @MAKEFLAGS_SILENT@ \
+ COPY_HEADERS_IF_SUBDIR=${includesubdir} \
+ COPY_HEADERS_DESTINATION=$$PWD/$@/Headers \
+ copy-headers-into-framework && \
+ ${INSTALL} -m 644 Info.plist $@/Info.plist && \
+ if test -f module.modulemap; then \
+ ${MKDIR_P} $@/Modules && \
+ ${INSTALL} -m 644 module.modulemap \
+ $@/Modules/module.modulemap; \
+ fi && \
+ ${LD} -o $@/$${out%.framework} \
+ ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${FRAMEWORK_LDFLAGS} \
+ ${FRAMEWORK_LDFLAGS_INSTALL_NAME} ${LDFLAGS} \
+ ${FRAMEWORK_LIBS} && \
+ ${CODESIGN} -fs ${CODESIGN_IDENTITY} $@; then \
+ ${LINK_OK}; \
+ else \
+ rm -fr $$out; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ else \
+ versiondir="$@/Versions/${LIB_MAJOR}"; \
+ if rm -fr $@ && \
+ ${MKDIR_P} $$versiondir && \
+ ${LN_S} ${LIB_MAJOR} $@/Versions/Current && \
+ ${MAKE} @MAKEFLAGS_SILENT@ \
+ COPY_HEADERS_IF_SUBDIR=${includesubdir} \
+ COPY_HEADERS_DESTINATION=$$PWD/$$versiondir/Headers \
+ copy-headers-into-framework && \
+ ${LN_S} Versions/Current/Headers $@/Headers && \
+ if test -f Info.plist; then \
+ ${MKDIR_P} $$versiondir/Resources && \
+ ${INSTALL} -m 644 Info.plist \
+ $$versiondir/Resources/Info.plist && \
+ ${LN_S} Versions/Current/Resources $@/Resources; \
+ fi && \
+ if test -f module.modulemap; then \
+ ${MKDIR_P} $$versiondir/Modules && \
+ ${INSTALL} -m 644 module.modulemap \
+ $$versiondir/Modules/module.modulemap && \
+ ${LN_S} Versions/Current/Modules $@/Modules; \
+ fi && \
+ ${LD} -o $$versiondir/$${out%.framework} \
+ ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${FRAMEWORK_LDFLAGS} \
+ ${FRAMEWORK_LDFLAGS_INSTALL_NAME} ${LDFLAGS} \
+ ${FRAMEWORK_LIBS} && \
+ ${LN_S} Versions/Current/$${out%.framework} \
+ $@/$${out%.framework} && \
+ ${CODESIGN} -fs ${CODESIGN_IDENTITY} $@; then \
+ ${LINK_OK}; \
+ else \
+ rm -fr $$out; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ fi
+
+copy-headers-into-framework:
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ cd $$i || exit 1; \
+ ${MAKE} @MAKEFLAGS_SILENT@ copy-headers-into-framework || \
+ exit $$?; \
+ cd .. || exit 1; \
+ done
+
+ if test x"${includesubdir}" = x"${COPY_HEADERS_IF_SUBDIR}"; then \
+ for i in "" ${INCLUDES}; do \
+ test x"$$i" = x"" && continue; \
+ ${MKDIR_P} \
+ $$(dirname ${COPY_HEADERS_DESTINATION}/$$i) || \
+ exit $$?; \
+ ${INSTALL} -m 644 $$i \
+ ${COPY_HEADERS_DESTINATION}/$$i || exit $$?; \
+ done \
+ fi
+
+${AMIGA_LIB} ${AMIGA_LIB_NOINST}: ${EXT_DEPS} ${AMIGA_LIB_OBJS_START} \
+ ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA}
+ ${LINK_STATUS}
+ if ${LD} -o $@ ${AMIGA_LIB_OBJS_START} ${AMIGA_LIB_OBJS} \
+ ${AMIGA_LIB_OBJS_EXTRA} ${AMIGA_LIB_LDFLAGS} \
+ ${AMIGA_LIB_LIBS}; then \
+ ${LINK_OK}; \
+ else \
+ ${LINK_FAILED}; \
+ fi
+
+${PLUGIN} ${PLUGIN_NOINST}: ${EXT_DEPS} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA}
+ ${LINK_STATUS}
+ out="$@"; \
+ if ${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}; then \
+ ${LINK_OK}; \
+ else \
+ rm -fr $$out; false; \
+ ${LINK_FAILED}; \
+ fi
+
+${BUNDLE} ${BUNDLE_NOINST}: ${EXT_DEPS} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA}
+ ${LINK_STATUS}
+ out="$@"; \
+ if rm -fr $$out && @LINK_BUNDLE@ && ${CODESIGN} -fs ${CODESIGN_IDENTITY} $$out; then \
+ ${LINK_OK}; \
+ else \
+ rm -fr $$out; false; \
+ ${LINK_FAILED}; \
+ fi
+
+${STATIC_LIB} ${STATIC_LIB_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA}
+ ${LINK_STATUS}
+ rm -f $@
+ if test x"${BUILD_AND_HOST_ARE_DARWIN}" = x"yes"; then \
+ if /usr/bin/libtool -static -o $@ ${OBJS} ${OBJS_EXTRA}; then \
+ ${LINK_OK}; \
+ else \
+ rm -f $@; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ else \
+ out="$@"; \
+ objs=""; \
+ ars=""; \
+ for i in ${OBJS} ${OBJS_EXTRA}; do \
+ case $$i in \
+ *.a) \
+ ars="$$ars $$i" \
+ ;; \
+ *.o) \
+ objs="$$objs $$i" \
+ ;; \
+ esac \
+ done; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ mkdir -p $$dir; \
+ cd $$dir; \
+ ${AR} x ../$$i; \
+ for j in *.o; do \
+ objs="$$objs $$dir/$$j"; \
+ done; \
+ cd ..; \
+ done; \
+ if ${AR} cr $@ $$objs && ${RANLIB} $@; then \
+ ${LINK_OK}; \
+ else \
+ rm -f $@; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ done; \
+ fi
+
+${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} \
+ ${LIB_OBJS_EXTRA}
+ ${LINK_STATUS}
+ rm -f $@
+ if test x"${BUILD_AND_HOST_ARE_DARWIN}" = x"yes"; then \
+ if /usr/bin/libtool -static -o $@ ${LIB_OBJS} \
+ ${LIB_OBJS_EXTRA}; then \
+ ${LINK_OK}; \
+ else \
+ rm -f $@; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ else \
+ out="$@"; \
+ objs=""; \
+ ars=""; \
+ for i in ${LIB_OBJS} ${LIB_OBJS_EXTRA}; do \
+ case $$i in \
+ *.a) \
+ ars="$$ars $$i" \
+ ;; \
+ *.o) \
+ objs="$$objs $$i" \
+ ;; \
+ esac \
+ done; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ mkdir -p $$dir; \
+ cd $$dir; \
+ ${AR} x ../$$i; \
+ for j in *.o; do \
+ objs="$$objs $$dir/$$j"; \
+ done; \
+ cd ..; \
+ done; \
+ if ${AR} cr $@ $$objs && ${RANLIB} $@; then \
+ ${LINK_OK}; \
+ else \
+ rm -f $@; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ done; \
+ fi
+
+${STATIC_AMIGA_LIB} ${STATIC_AMIGA_LIB_NOINST}: ${EXT_DEPS} ${AMIGA_LIB_OBJS} \
+ ${AMIGA_LIB_OBJS_EXTRA}
+ ${LINK_STATUS}
+ rm -f $@
+ out="$@"; \
+ objs=""; \
+ ars=""; \
+ for i in ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA}; do \
+ case $$i in \
+ *.a) \
+ ars="$$ars $$i" \
+ ;; \
+ *.o) \
+ objs="$$objs $$i" \
+ ;; \
+ esac \
+ done; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ mkdir -p $$dir; \
+ cd $$dir; \
+ ${AR} x ../$$i; \
+ for j in *.o; do \
+ objs="$$objs $$dir/$$j"; \
+ done; \
+ cd ..; \
+ done; \
+ if ${AR} cr $@ $$objs && ${RANLIB} $@; then \
+ ${LINK_OK}; \
+ else \
+ rm -f $@; false; \
+ ${LINK_FAILED}; \
+ fi; \
+ for i in $$ars; do \
+ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \
+ rm -fr $$dir; \
+ done
+
+locales: ${MO_FILES}
+
+.c.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} ${CFLAGS_$@} ${DEP_CFLAGS} \
+ -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.c.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} ${CFLAGS_$@} \
+ ${DEP_CFLAGS} -c -o $@ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.c.amigalib.o:
+ ${COMPILE_AMIGA_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${AMIGA_LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} \
+ ${CFLAGS_$@} ${DEP_CFLAGS} -c -o $@ $<; then \
+ ${COMPILE_AMIGA_LIB_OK}; \
+ else \
+ ${COMPILE_AMIGA_LIB_FAILED}; \
+ fi
+.c.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} \
+ ${CFLAGS_$@} ${DEP_CFLAGS} -c -o $@ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+.cc.o .cxx.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${CXXFLAGS_$<} ${CXXFLAGS_$@} \
+ ${DEP_CXXFLAGS} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.cc.lib.o .cxx.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CXX} ${LIB_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} ${CXXFLAGS_$<} \
+ ${CXXFLAGS_$@} ${DEP_CXXFLAGS} -c -o $@ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.cc.amigalib.o .cxx.amigalib.o:
+ ${COMPILE_AMIGA_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CXX} ${AMIGA_LIB_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} ${CXXFLAGS_$<} \
+ ${CXXFLAGS_$@} ${DEP_CXXFLAGS} -c -o $@ $<; then \
+ ${COMPILE_AMIGA_LIB_OK}; \
+ else \
+ ${COMPILE_AMIGA_LIB_FAILED}; \
+ fi
+.cc.plugin.o .cxx.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CXX} ${PLUGIN_CFLAGS} ${CXXFLAGS} ${CPPFLAGS} ${CXXFLAGS_$<} \
+ ${CXXFLAGS_$@} ${DEP_CXXFLAGS} -c -o $@ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+.d.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if test x"$(basename ${DC})" = x"dmd"; then \
+ if ${DC} ${DFLAGS} -c -of$@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi \
+ else \
+ if ${DC} ${DFLAGS} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi \
+ fi
+
+.erl.beam:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${ERLC} ${ERLCFLAGS} -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+
+.java.class:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${JAVAC} ${JAVACFLAGS} $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+
+.m.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJC} ${OBJCFLAGS} ${CPPFLAGS} ${OBJCFLAGS_$<} ${OBJCFLAGS_$@} \
+ ${DEP_OBJCFLAGS} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.m.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJC} ${LIB_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} ${OBJCFLAGS_$<} \
+ ${OBJCFLAGS_$@} ${DEP_OBJCFLAGS} -c -o $@ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.m.amigalib.o:
+ ${COMPILE_AMIGA_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJC} ${AMIGA_LIB_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} \
+ ${OBJCFLAGS_$<} ${OBJCFLAGS_$@} ${DEP_OBJCFLAGS} -c -o $@ $<; then \
+ ${COMPILE_AMIGA_LIB_OK}; \
+ else \
+ ${COMPILE_AMIGA_LIB_FAILED}; \
+ fi
+.m.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJC} ${PLUGIN_CFLAGS} ${OBJCFLAGS} ${CPPFLAGS} ${OBJCFLAGS_$<} \
+ ${OBJCFLAGS_$@} ${DEP_OBJCFLAGS} -c -o $@ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+.mm.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJCXX} ${OBJCXXFLAGS} ${CPPFLAGS} ${OBJCXXFLAGS_$<} \
+ ${OBJCXXFLAGS_$@} ${DEP_OBJCXXFLAGS} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.mm.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJCXX} ${LIB_CFLAGS} ${OBJCXXFLAGS} ${CPPFLAGS} \
+ ${OBJCXXFLAGS_$<} ${OBJCXXFLAGS_$@} ${DEP_OBJCXXFLAGS} -c -o $@ \
+ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.mm.amigalib.o:
+ ${COMPILE_AMIGA_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJCXX} ${AMIGA_LIB_CFLAGS} ${OBJCXXFLAGS} ${CPPFLAGS} \
+ ${OBJCXXFLAGS_$<} ${OBJCXXFLAGS_$@} ${DEP_OBJCXXFLAGS} -c -o $@ \
+ $<; then \
+ ${COMPILE_AMIGA_LIB_OK}; \
+ else \
+ ${COMPILE_AMIGA_LIB_FAILED}; \
+ fi
+.mm.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${OBJCXX} ${PLUGIN_CFLAGS} ${OBJCXXFLAGS} ${CPPFLAGS} \
+ ${OBJCXXFLAGS_$<} ${OBJCXXFLAGS_$@} ${DEP_OBJCXXFLAGS} -c -o $@ \
+ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+.po.mo:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${MSGFMT} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+
+.py.pyc:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${PYTHON} ${PYTHON_FLAGS} -c \
+ "import py_compile; py_compile.compile('$<')"; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+
+.rc.o .rc.lib.o .rc.plugin.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${RC} ${RCFLAGS} ${CPPFLAGS} -J rc -O coff -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+
+.S.o .S.amigalib.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${AS} ${ASFLAGS} ${CPPFLAGS} ${ASFLAGS_$<} ${ASFLAGS_$@} \
+ ${DEP_ASFLAGS} -c -o $@ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.S.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${AS} ${LIB_CFLAGS} ${ASFLAGS} ${CPPFLAGS} ${ASFLAGS_$<} \
+ ${ASFLAGS_$@} ${DEP_ASFLAGS} -c -o $@ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.S.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${AS} ${PLUGIN_CFLAGS} ${ASFLAGS} ${CPPFLAGS} ${ASFLAGS_$<} \
+ ${ASFLAGS_$@} ${DEP_ASFLAGS} -c -o $@ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+.xpm.o:
+ ${COMPILE_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} ${CFLAGS_$@} -x c -c -o $@ \
+ $<; then \
+ ${COMPILE_OK}; \
+ else \
+ ${COMPILE_FAILED}; \
+ fi
+.xpm.lib.o:
+ ${COMPILE_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} ${CFLAGS_$@} \
+ -x c -c -o $@ $<; then \
+ ${COMPILE_LIB_OK}; \
+ else \
+ ${COMPILE_LIB_FAILED}; \
+ fi
+.xpm.amigalib.o:
+ ${COMPILE_AMIGA_LIB_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${AMIGA_LIB_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} \
+ ${CFLAGS_$@} -x c -c -o $@ $<; then \
+ ${COMPILE_AMIGA_LIB_OK}; \
+ else \
+ ${COMPILE_AMIGA_LIB_FAILED}; \
+ fi
+.xpm.plugin.o:
+ ${COMPILE_PLUGIN_STATUS}
+ in="$<"; \
+ out="$@"; \
+ if ${CC} ${PLUGIN_CFLAGS} ${CFLAGS} ${CPPFLAGS} ${CFLAGS_$<} \
+ ${CFLAGS_$@} -x c -c -o $@ $<; then \
+ ${COMPILE_PLUGIN_OK}; \
+ else \
+ ${COMPILE_PLUGIN_FAILED}; \
+ fi
+
+install: all install-extra
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ ${DIR_ENTER}; \
+ ${MAKE} @MAKEFLAGS_SILENT@ install || exit $$?; \
+ ${DIR_LEAVE}; \
+ done
+
+ for i in "" ${SHARED_LIB}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} ${DESTDIR}${libdir} @INSTALL_LIB@; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${FRAMEWORK}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ rm -fr ${DESTDIR}${prefix}/Library/Frameworks/$$i; \
+ if ${MKDIR_P} ${DESTDIR}${prefix}/Library/Frameworks && \
+ cp -R $$i ${DESTDIR}${prefix}/Library/Frameworks/; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${AMIGA_LIB}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} ${DESTDIR}${amigalibdir} && \
+ ${INSTALL} -m 755 $$i ${DESTDIR}${amigalibdir}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${STATIC_LIB} ${STATIC_PIC_LIB} ${STATIC_AMIGA_LIB}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} ${DESTDIR}${libdir} && \
+ ${INSTALL} -m 644 $$i ${DESTDIR}${libdir}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${PLUGIN}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} ${DESTDIR}${plugindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${BUNDLE}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ rm -fr ${DESTDIR}${bundledir}/$$i; \
+ if ${MKDIR_P} ${DESTDIR}${bundledir} && \
+ cp -R $$i ${DESTDIR}${bundledir}/; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${DATA}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} $$(dirname \
+ ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i) && \
+ ${INSTALL} -m 644 $$i \
+ ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${PROG}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} ${DESTDIR}${bindir} && \
+ ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ if test x"${INSTALL_INCLUDES}" = x"yes"; then \
+ for i in "" ${INCLUDES}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ if ${MKDIR_P} $$(dirname \
+ ${DESTDIR}${includedir}/${includesubdir}/$$i) && \
+ ${INSTALL} -m 644 $$i \
+ ${DESTDIR}${includedir}/${includesubdir}/$$i; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done \
+ fi
+
+ for i in "" ${MO_FILES}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ dest="${localedir}/$${i%.mo}/LC_MESSAGES/${localename}.mo"; \
+ dest="${DESTDIR}$$dest"; \
+ if ${MKDIR_P} ${DESTDIR}${localedir}/$${i%.mo}/LC_MESSAGES && \
+ ${INSTALL} -m 644 $$i $$dest; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+ for i in "" ${MAN}; do \
+ test x"$$i" = x"" && continue; \
+ ${INSTALL_STATUS}; \
+ dest="${DESTDIR}${mandir}/${mansubdir}/$$i"; \
+ if ${MKDIR_P} ${DESTDIR}${mandir}/${mansubdir} && \
+ ${INSTALL} -m 644 $$i $$dest; then \
+ ${INSTALL_OK}; \
+ else \
+ ${INSTALL_FAILED}; \
+ fi \
+ done
+
+install-extra:
+
+uninstall:
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ ${DIR_ENTER}; \
+ ${MAKE} @MAKEFLAGS_SILENT@ uninstall || exit $$?; \
+ ${DIR_LEAVE}; \
+ done
+
+ for i in "" ${SHARED_LIB}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${libdir}/$$i \
+ -o -f ${DESTDIR}${bindir}/$$i; then \
+ if : @UNINSTALL_LIB@; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi; \
+ done
+
+ for i in "" ${FRAMEWORK}; do \
+ test x"$$i" = x"" && continue; \
+ if test -d ${DESTDIR}${prefix}/Library/Frameworks/$$i; then \
+ if rm -fr ${DESTDIR}${prefix}/Library/Frameworks/$$i; \
+ then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+ rmdir ${DESTDIR}${prefix}/Library/Frameworks >/dev/null 2>&1 || true
+ rmdir ${DESTDIR}${prefix}/Library >/dev/null 2>&1 || true
+
+ for i in "" ${STATIC_LIB} ${STATIC_PIC_LIB} ${STATIC_AMIGA_LIB}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${libdir}/$$i; then \
+ if rm -f ${DESTDIR}${libdir}/$$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+ for i in "" ${PLUGIN}; do \
+ test x"$$i" = x"" && continue; \
+ if test -e ${DESTDIR}${plugindir}/$$i; then \
+ if rm -f ${DESTDIR}${plugindir}/$$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+ rmdir ${DESTDIR}${plugindir} >/dev/null 2>&1 || true
+
+ for i in "" ${BUNDLE}; do \
+ test x"$$i" = x"" && continue; \
+ if test -d ${DESTDIR}${bundledir}/$$i; then \
+ if rm -fr ${DESTDIR}${bundledir}/$$i; \
+ then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+ rmdir ${DESTDIR}${bundledir} >/dev/null 2>&1 || true
+ rmdir ${DESTDIR}${prefix}/Library >/dev/null 2>&1 || true
+
+ for i in "" ${DATA}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; then \
+ if rm -f ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; \
+ then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi; \
+ rmdir "$$(dirname ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i)" \
+ >/dev/null 2>&1 || true; \
+ done
+ rmdir ${DESTDIR}${datadir}/${PACKAGE_NAME} >/dev/null 2>&1 || true
+
+ for i in "" ${PROG}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${bindir}/$$i; then \
+ if rm -f ${DESTDIR}${bindir}/$$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+ for i in "" ${INCLUDES}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${includedir}/${includesubdir}/$$i; then \
+ if rm -f ${DESTDIR}${includedir}/${includesubdir}/$$i; \
+ then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+ rmdir ${DESTDIR}${includedir}/${includesubdir} >/dev/null 2>&1 || true
+
+ for i in "" ${MO_FILES}; do \
+ test x"$$i" = x"" && continue; \
+ mo="${localedir}/$${i%.mo}/LC_MESSAGES/${localename}.mo"; \
+ mo="${DESTDIR}$$mo"; \
+ if test -f $$mo; then \
+ if rm -f $$mo; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+ for i in "" ${MAN}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f ${DESTDIR}${mandir}/${mansubdir}/$$i; then \
+ if rm -f ${DESTDIR}${mandir}/${mansubdir}/$$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+ ${MAKE} @MAKEFLAGS_SILENT@ uninstall-extra
+
+uninstall-extra:
+
+clean:
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ ${DIR_ENTER}; \
+ ${MAKE} @MAKEFLAGS_SILENT@ clean || exit $$?; \
+ ${DIR_LEAVE}; \
+ done
+
+ : >.deps
+
+ for i in "" ${DEPS} ${OBJS} ${OBJS_EXTRA} ${LIB_OBJS} \
+ ${LIB_OBJS_EXTRA} ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_START} \
+ ${AMIGA_LIB_OBJS_EXTRA} ${PLUGIN_OBJS} ${PROG} ${PROG_NOINST} \
+ ${SHARED_LIB} ${SHARED_LIB_NOINST} ${AMIGA_LIB} \
+ ${AMIGA_LIB_NOINST} ${STATIC_LIB} ${STATIC_LIB_NOINST} \
+ ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${STATIC_AMIGA_LIB} \
+ ${STATIC_AMIGA_LIB_NOINST} ${FRAMEWORK} ${FRAMEWORK_NOINST} \
+ ${PLUGIN} ${PLUGIN_NOINST} ${BUNDLE} ${BUNDLE_NOINST} \
+ ${CLEAN_LIB} ${MO_FILES} ${CLEAN}; do \
+ test x"$$i" = x"" && continue; \
+ if test -f $$i -o -d $$i; then \
+ if rm -fr $$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+distclean: clean
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ ${DIR_ENTER}; \
+ ${MAKE} @MAKEFLAGS_SILENT@ distclean || exit $$?; \
+ ${DIR_LEAVE}; \
+ done
+
+ for i in "" ${DISTCLEAN} .deps *~; do \
+ test x"$$i" = x"" && continue; \
+ if test -f $$i -o -d $$i; then \
+ if rm -fr $$i; then \
+ ${DELETE_OK}; \
+ else \
+ ${DELETE_FAILED}; \
+ fi \
+ fi \
+ done
+
+print-hierarchy:
+ for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \
+ test x"$$i" = x"" && continue; \
+ echo ${PRINT_HIERARCHY_PREFIX}$$i; \
+ cd $$i || exit $$?; \
+ ${MAKE} @MAKEFLAGS_SILENT@ PRINT_HIERARCHY_PREFIX=$$i/ \
+ print-hierarchy || exit $$?; \
+ cd .. || exit $$?; \
+ done
+
+print-var:
+ printf '%s\n' '${${VAR}}'
+
+DIR_ENTER = printf "@TERM_EL@@TERM_SETAF6@Entering directory @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF6@.@TERM_SGR0@\n" "$$i"; cd $$i || exit $$?
+DIR_LEAVE = printf "@TERM_EL@@TERM_SETAF6@Leaving directory @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF6@.@TERM_SGR0@\n" "$$i"; cd .. || exit $$?
+COMPILE_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r" "$<"
+COMPILE_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n" "$<"
+COMPILE_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n" "$<"; exit $$err
+COMPILE_LIB_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF3@ (lib)...@TERM_SGR0@\r" "$<"
+COMPILE_LIB_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF2@ (lib).@TERM_SGR0@\n" "$<"
+COMPILE_LIB_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@ (lib)!@TERM_SGR0@\n" "$<"; exit $$err
+COMPILE_AMIGA_LIB_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF3@ (Amiga lib)...@TERM_SGR0@\r" "$<"
+COMPILE_AMIGA_LIB_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF2@ (Amiga lib).@TERM_SGR0@\n" "$<"
+COMPILE_AMIGA_LIB_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@ (Amiga lib)!@TERM_SGR0@\n" "$<"; exit $$err
+COMPILE_PLUGIN_STATUS = printf "@TERM_EL@@TERM_SETAF3@Compiling @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF3@ (plugin)...@TERM_SGR0@\r" "$<"
+COMPILE_PLUGIN_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully compiled @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF2@ (plugin).@TERM_SGR0@\n" "$<"
+COMPILE_PLUGIN_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to compile @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@ (plugin)!@TERM_SGR0@\n" "$<"; exit $$err
+LINK_STATUS = printf "@TERM_EL@@TERM_SETAF3@Linking @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r"
+LINK_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully linked @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n"
+LINK_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to link @TERM_BOLD@$@@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n"; exit $$err
+INSTALL_STATUS = printf "@TERM_EL@@TERM_SETAF3@Installing @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF3@...@TERM_SGR0@\r" "$$i"
+INSTALL_OK = printf "@TERM_EL@@TERM_SETAF2@Successfully installed @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF2@.@TERM_SGR0@\n" "$$i"
+INSTALL_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to install @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n" "$$i"; exit $$err
+DELETE_OK = printf "@TERM_EL@@TERM_SETAF4@Deleted @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF4@.@TERM_SGR0@\n" "$$i"
+DELETE_FAILED = err=$$?; printf "@TERM_EL@@TERM_SETAF1@Failed to delete @TERM_BOLD@%s@TERM_SGR0@@TERM_SETAF1@!@TERM_SGR0@\n" "$$i"; exit $$err
+
+.CURDIR ?= .
+-include ${.CURDIR}/.deps
ADDED configure.ac
Index: configure.ac
==================================================================
--- /dev/null
+++ configure.ac
@@ -0,0 +1,44 @@
+AC_INIT(cube, 0.1, js@nil.im)
+AC_CONFIG_SRCDIR(src)
+AC_CONFIG_AUX_DIR(build-aux)
+AC_CONFIG_MACRO_DIR(build-aux/m4)
+
+for i in configure.ac build-aux/m4/*; do
+ AS_IF([test $i -nt configure], [
+ AC_MSG_ERROR([$i is newer than configure! Run ./autogen.sh!])
+ ])
+done
+
+BUILDSYS_INIT
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_PROG_CXX
+AC_PROG_CXXCPP
+
+AC_PATH_TOOL(AR, ar)
+AC_PATH_TOOL(RANLIB, ranlib)
+
+PKG_CHECK_MODULES(SDL, [
+ sdl12_compat >= 1.2
+ SDL_image >= 1.2
+ SDL_mixer >= 1.2
+])
+AC_SUBST(SDL_CFLAGS)
+AC_SUBST(SDL_LIBS)
+
+PKG_CHECK_MODULES(GL, gl)
+PKG_CHECK_MODULES(GLU, glu)
+PKG_CHECK_MODULES(ZLIB, zlib)
+
+case "$host_os" in
+mingw32*)
+ ;;
+*)
+ PKG_CHECK_MODULES(X11, x11)
+ ;;
+esac
+
+AC_CONFIG_FILES([buildsys.mk extra.mk])
+AC_OUTPUT
ADDED enet/Makefile
Index: enet/Makefile
==================================================================
--- /dev/null
+++ enet/Makefile
@@ -0,0 +1,15 @@
+STATIC_LIB_NOINST = libenet.a
+
+SRCS = callbacks.c \
+ host.c \
+ list.c \
+ memory.c \
+ packet.c \
+ peer.c \
+ protocol.c \
+ unix.c \
+ win32.c
+
+include ../buildsys.mk
+
+CPPFLAGS += -Iinclude
Index: enet/include/enet/enet.h
==================================================================
--- enet/include/enet/enet.h
+++ enet/include/enet/enet.h
@@ -9,13 +9,13 @@
extern "C"
{
#endif
#include
-
+#include
-#ifdef WIN32
+#ifdef _WIN32
#include "enet/win32.h"
#else
#include "enet/unix.h"
#endif
Index: enet/protocol.c
==================================================================
--- enet/protocol.c
+++ enet/protocol.c
@@ -1127,11 +1127,11 @@
currentPeer -> packetsSent > 0)
{
enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
#ifdef ENET_DEBUG
-#ifdef WIN32
+#ifdef _WIN32
printf (
#else
fprintf (stderr,
#endif
"peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands));
Index: enet/unix.c
==================================================================
--- enet/unix.c
+++ enet/unix.c
@@ -1,10 +1,10 @@
/**
@file unix.c
@brief ENet Unix system specific functions
*/
-#ifndef WIN32
+#ifndef _WIN32
#include
#include
#include
#include
@@ -23,11 +23,11 @@
#ifdef HAS_POLL
#include
#endif
-#ifndef HAS_SOCKLEN_T
+#if 0
typedef int socklen_t;
#endif
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
Index: enet/win32.c
==================================================================
--- enet/win32.c
+++ enet/win32.c
@@ -1,10 +1,10 @@
/**
@file win32.c
@brief ENet Win32 system specific functions
*/
-#ifdef WIN32
+#ifdef _WIN32
#include
#define ENET_BUILDING_LIB 1
#include "enet/enet.h"
ADDED extra.mk.in
Index: extra.mk.in
==================================================================
--- /dev/null
+++ extra.mk.in
@@ -0,0 +1,10 @@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_LIBS = @SDL_LIBS@
+X11_CFLAGS = @X11_CFLAGS@
+X11_LIBS = @X11_LIBS@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
ADDED src/Makefile
Index: src/Makefile
==================================================================
--- /dev/null
+++ src/Makefile
@@ -0,0 +1,52 @@
+PROG = client
+
+SRCS = client.o \
+ clientextras.o \
+ clientgame.o \
+ clients2c.o \
+ command.o \
+ console.o \
+ editing.o \
+ entities.o \
+ main.o \
+ menus.o \
+ monster.o \
+ physics.o \
+ rendercubes.o \
+ renderextras.o \
+ rendergl.o \
+ rendermd2.o \
+ renderparticles.o \
+ rendertext.o \
+ rndmap.o \
+ savegamedemo.o \
+ server.o \
+ serverbrowser.o \
+ serverms.o \
+ serverutil.o \
+ sound.o \
+ tools.o \
+ weapon.o \
+ world.o \
+ worldio.o \
+ worldlight.o \
+ worldocull.o \
+ worldrender.o
+
+include ../buildsys.mk
+include ../extra.mk
+
+CPPFLAGS += -I../enet/include \
+ ${SDL_CFLAGS} \
+ ${GL_CFLAGS} \
+ ${GLU_CFLAGS} \
+ ${X11_CFLAGS} \
+ ${ZLIB_CFLAGS}
+CXXFLAGS += -fpermissive
+LIBS += -L../enet -lenet \
+ ${SDL_LIBS} \
+ ${GL_LIBS} \
+ ${GLU_LIBS} \
+ ${X11_LIBS} \
+ ${ZLIB_LIBS}
+LD = ${CXX}
DELETED src/client.cpp
Index: src/client.cpp
==================================================================
--- src/client.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-// client.cpp, mostly network related client game code
-
-#include "cube.h"
-
-ENetHost *clienthost = NULL;
-int connecting = 0;
-int connattempts = 0;
-int disconnecting = 0;
-int clientnum = -1; // our client id in the game
-bool c2sinit = false; // whether we need to tell the other clients our stats
-
-int getclientnum() { return clientnum; };
-
-bool multiplayer()
-{
- // check not correct on listen server?
- if(clienthost) conoutf("operation not available in multiplayer");
- return clienthost!=NULL;
-};
-
-bool allowedittoggle()
-{
- bool allow = !clienthost || gamemode==1;
- if(!allow) conoutf("editing in multiplayer requires coopedit mode (1)");
- return allow;
-};
-
-VARF(rate, 0, 0, 25000, if(clienthost && (!rate || rate>1000)) enet_host_bandwidth_limit (clienthost, rate, rate));
-
-void throttle();
-
-VARF(throttle_interval, 0, 5, 30, throttle());
-VARF(throttle_accel, 0, 2, 32, throttle());
-VARF(throttle_decel, 0, 2, 32, throttle());
-
-void throttle()
-{
- if(!clienthost || connecting) return;
- assert(ENET_PEER_PACKET_THROTTLE_SCALE==32);
- enet_peer_throttle_configure(clienthost->peers, throttle_interval*1000, throttle_accel, throttle_decel);
-};
-
-void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); };
-void newteam(char *name) { c2sinit = false; strn0cpy(player1->team, name, 5); };
-
-COMMANDN(team, newteam, ARG_1STR);
-COMMANDN(name, newname, ARG_1STR);
-
-void writeclientinfo(FILE *f)
-{
- fprintf(f, "name \"%s\"\nteam \"%s\"\n", player1->name, player1->team);
-};
-
-void connects(char *servername)
-{
- disconnect(1); // reset state
- addserver(servername);
-
- conoutf("attempting to connect to %s", servername);
- ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
- if(enet_address_set_host(&address, servername) < 0)
- {
- conoutf("could not resolve server %s", servername);
- return;
- };
-
- clienthost = enet_host_create(NULL, 1, rate, rate);
-
- if(clienthost)
- {
- enet_host_connect(clienthost, &address, 1);
- enet_host_flush(clienthost);
- connecting = lastmillis;
- connattempts = 0;
- }
- else
- {
- conoutf("could not connect to server");
- disconnect();
- };
-};
-
-void disconnect(int onlyclean, int async)
-{
- if(clienthost)
- {
- if(!connecting && !disconnecting)
- {
- enet_peer_disconnect(clienthost->peers);
- enet_host_flush(clienthost);
- disconnecting = lastmillis;
- };
- if(clienthost->peers->state != ENET_PEER_STATE_DISCONNECTED)
- {
- if(async) return;
- enet_peer_reset(clienthost->peers);
- };
- enet_host_destroy(clienthost);
- };
-
- if(clienthost && !connecting) conoutf("disconnected");
- clienthost = NULL;
- connecting = 0;
- connattempts = 0;
- disconnecting = 0;
- clientnum = -1;
- c2sinit = false;
- player1->lifesequence = 0;
- loopv(players) zapdynent(players[i]);
-
- localdisconnect();
-
- if(!onlyclean) { stop(); localconnect(); };
-};
-
-void trydisconnect()
-{
- if(!clienthost)
- {
- conoutf("not connected");
- return;
- };
- if(connecting)
- {
- conoutf("aborting connection attempt");
- disconnect();
- return;
- };
- conoutf("attempting to disconnect...");
- disconnect(0, !disconnecting);
-};
-
-string ctext;
-void toserver(char *text) { conoutf("%s:\f %s", player1->name, text); strn0cpy(ctext, text, 80); };
-void echo(char *text) { conoutf("%s", text); };
-
-COMMAND(echo, ARG_VARI);
-COMMANDN(say, toserver, ARG_VARI);
-COMMANDN(connect, connects, ARG_1STR);
-COMMANDN(disconnect, trydisconnect, ARG_NONE);
-
-// collect c2s messages conveniently
-
-vector messages;
-
-void addmsg(int rel, int num, int type, ...)
-{
- if(demoplayback) return;
- if(num!=msgsizelookup(type)) { sprintf_sd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); };
- if(messages.length()==100) { conoutf("command flood protection (type %d)", type); return; };
- ivector &msg = messages.add();
- msg.add(num);
- msg.add(rel);
- msg.add(type);
- va_list marker;
- va_start(marker, type);
- loopi(num-1) msg.add(va_arg(marker, int));
- va_end(marker);
-};
-
-void server_err()
-{
- conoutf("server network error, disconnecting...");
- disconnect();
-};
-
-int lastupdate = 0, lastping = 0;
-string toservermap;
-bool senditemstoserver = false; // after a map change, since server doesn't have map data
-
-string clientpassword;
-void password(char *p) { strcpy_s(clientpassword, p); };
-COMMAND(password, ARG_1STR);
-
-bool netmapstart() { senditemstoserver = true; return clienthost!=NULL; };
-
-void initclientnet()
-{
- ctext[0] = 0;
- toservermap[0] = 0;
- clientpassword[0] = 0;
- newname("unnamed");
- newteam("red");
-};
-
-void sendpackettoserv(void *packet)
-{
- if(clienthost) { enet_host_broadcast(clienthost, 0, (ENetPacket *)packet); enet_host_flush(clienthost); }
- else localclienttoserver((ENetPacket *)packet);
-}
-
-void c2sinfo(dynent *d) // send update to the server
-{
- if(clientnum<0) return; // we haven't had a welcome message from the server yet
- if(lastmillis-lastupdate<40) return; // don't update faster than 25fps
- ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0);
- uchar *start = packet->data;
- uchar *p = start+2;
- bool serveriteminitdone = false;
- if(toservermap[0]) // suggest server to change map
- { // do this exclusively as map change may invalidate rest of update
- packet->flags = ENET_PACKET_FLAG_RELIABLE;
- putint(p, SV_MAPCHANGE);
- sendstring(toservermap, p);
- toservermap[0] = 0;
- putint(p, nextmode);
- }
- else
- {
- putint(p, SV_POS);
- putint(p, clientnum);
- putint(p, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes
- putint(p, (int)(d->o.y*DMF));
- putint(p, (int)(d->o.z*DMF));
- putint(p, (int)(d->yaw*DAF));
- putint(p, (int)(d->pitch*DAF));
- putint(p, (int)(d->roll*DAF));
- putint(p, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte
- putint(p, (int)(d->vel.y*DVF));
- putint(p, (int)(d->vel.z*DVF));
- // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3
- putint(p, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) );
-
- if(senditemstoserver)
- {
- packet->flags = ENET_PACKET_FLAG_RELIABLE;
- putint(p, SV_ITEMLIST);
- if(!m_noitems) putitems(p);
- putint(p, -1);
- senditemstoserver = false;
- serveriteminitdone = true;
- };
- if(ctext[0]) // player chat, not flood protected for now
- {
- packet->flags = ENET_PACKET_FLAG_RELIABLE;
- putint(p, SV_TEXT);
- sendstring(ctext, p);
- ctext[0] = 0;
- };
- if(!c2sinit) // tell other clients who I am
- {
- packet->flags = ENET_PACKET_FLAG_RELIABLE;
- c2sinit = true;
- putint(p, SV_INITC2S);
- sendstring(player1->name, p);
- sendstring(player1->team, p);
- putint(p, player1->lifesequence);
- };
- loopv(messages) // send messages collected during the previous frames
- {
- ivector &msg = messages[i];
- if(msg[1]) packet->flags = ENET_PACKET_FLAG_RELIABLE;
- loopi(msg[0]) putint(p, msg[i+2]);
- };
- messages.setsize(0);
- if(lastmillis-lastping>250)
- {
- putint(p, SV_PING);
- putint(p, lastmillis);
- lastping = lastmillis;
- };
- };
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- incomingdemodata(start, p-start, true);
- if(clienthost) { enet_host_broadcast(clienthost, 0, packet); enet_host_flush(clienthost); }
- else localclienttoserver(packet);
- lastupdate = lastmillis;
- if(serveriteminitdone) loadgamerest(); // hack
-};
-
-void gets2c() // get updates from the server
-{
- ENetEvent event;
- if(!clienthost) return;
- if(connecting && lastmillis/3000 > connecting/3000)
- {
- conoutf("attempting to connect...");
- connecting = lastmillis;
- ++connattempts;
- if(connattempts > 3)
- {
- conoutf("could not connect to server");
- disconnect();
- return;
- };
- };
- while(clienthost!=NULL && enet_host_service(clienthost, &event, 0)>0)
- switch(event.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- conoutf("connected to server");
- connecting = 0;
- throttle();
- break;
-
- case ENET_EVENT_TYPE_RECEIVE:
- if(disconnecting) conoutf("attempting to disconnect...");
- else localservertoclient(event.packet->data, event.packet->dataLength);
- enet_packet_destroy(event.packet);
- break;
-
- case ENET_EVENT_TYPE_DISCONNECT:
- if(disconnecting) disconnect();
- else server_err();
- return;
- }
-};
-
ADDED src/client.cxx
Index: src/client.cxx
==================================================================
--- /dev/null
+++ src/client.cxx
@@ -0,0 +1,309 @@
+// client.cpp, mostly network related client game code
+
+#include "cube.h"
+
+ENetHost *clienthost = NULL;
+int connecting = 0;
+int connattempts = 0;
+int disconnecting = 0;
+int clientnum = -1; // our client id in the game
+bool c2sinit = false; // whether we need to tell the other clients our stats
+
+int getclientnum() { return clientnum; };
+
+bool multiplayer()
+{
+ // check not correct on listen server?
+ if(clienthost) conoutf("operation not available in multiplayer");
+ return clienthost!=NULL;
+};
+
+bool allowedittoggle()
+{
+ bool allow = !clienthost || gamemode==1;
+ if(!allow) conoutf("editing in multiplayer requires coopedit mode (1)");
+ return allow;
+};
+
+VARF(rate, 0, 0, 25000, if(clienthost && (!rate || rate>1000)) enet_host_bandwidth_limit (clienthost, rate, rate));
+
+void throttle();
+
+VARF(throttle_interval, 0, 5, 30, throttle());
+VARF(throttle_accel, 0, 2, 32, throttle());
+VARF(throttle_decel, 0, 2, 32, throttle());
+
+void throttle()
+{
+ if(!clienthost || connecting) return;
+ assert(ENET_PEER_PACKET_THROTTLE_SCALE==32);
+ enet_peer_throttle_configure(clienthost->peers, throttle_interval*1000, throttle_accel, throttle_decel);
+};
+
+void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); };
+void newteam(char *name) { c2sinit = false; strn0cpy(player1->team, name, 5); };
+
+COMMANDN(team, newteam, ARG_1STR);
+COMMANDN(name, newname, ARG_1STR);
+
+void writeclientinfo(FILE *f)
+{
+ fprintf(f, "name \"%s\"\nteam \"%s\"\n", player1->name, player1->team);
+};
+
+void connects(char *servername)
+{
+ disconnect(1); // reset state
+ addserver(servername);
+
+ conoutf("attempting to connect to %s", servername);
+ ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
+ if(enet_address_set_host(&address, servername) < 0)
+ {
+ conoutf("could not resolve server %s", servername);
+ return;
+ };
+
+ clienthost = enet_host_create(NULL, 1, rate, rate);
+
+ if(clienthost)
+ {
+ enet_host_connect(clienthost, &address, 1);
+ enet_host_flush(clienthost);
+ connecting = lastmillis;
+ connattempts = 0;
+ }
+ else
+ {
+ conoutf("could not connect to server");
+ disconnect();
+ };
+};
+
+void disconnect(int onlyclean, int async)
+{
+ if(clienthost)
+ {
+ if(!connecting && !disconnecting)
+ {
+ enet_peer_disconnect(clienthost->peers);
+ enet_host_flush(clienthost);
+ disconnecting = lastmillis;
+ };
+ if(clienthost->peers->state != ENET_PEER_STATE_DISCONNECTED)
+ {
+ if(async) return;
+ enet_peer_reset(clienthost->peers);
+ };
+ enet_host_destroy(clienthost);
+ };
+
+ if(clienthost && !connecting) conoutf("disconnected");
+ clienthost = NULL;
+ connecting = 0;
+ connattempts = 0;
+ disconnecting = 0;
+ clientnum = -1;
+ c2sinit = false;
+ player1->lifesequence = 0;
+ loopv(players) zapdynent(players[i]);
+
+ localdisconnect();
+
+ if(!onlyclean) { stop(); localconnect(); };
+};
+
+void trydisconnect()
+{
+ if(!clienthost)
+ {
+ conoutf("not connected");
+ return;
+ };
+ if(connecting)
+ {
+ conoutf("aborting connection attempt");
+ disconnect();
+ return;
+ };
+ conoutf("attempting to disconnect...");
+ disconnect(0, !disconnecting);
+};
+
+string ctext;
+void toserver(char *text) { conoutf("%s:\f %s", player1->name, text); strn0cpy(ctext, text, 80); };
+void echo(char *text) { conoutf("%s", text); };
+
+COMMAND(echo, ARG_VARI);
+COMMANDN(say, toserver, ARG_VARI);
+COMMANDN(connect, connects, ARG_1STR);
+COMMANDN(disconnect, trydisconnect, ARG_NONE);
+
+// collect c2s messages conveniently
+
+vector messages;
+
+void addmsg(int rel, int num, int type, ...)
+{
+ if(demoplayback) return;
+ if(num!=msgsizelookup(type)) { sprintf_sd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); };
+ if(messages.length()==100) { conoutf("command flood protection (type %d)", type); return; };
+ ivector &msg = messages.add();
+ msg.add(num);
+ msg.add(rel);
+ msg.add(type);
+ va_list marker;
+ va_start(marker, type);
+ loopi(num-1) msg.add(va_arg(marker, int));
+ va_end(marker);
+};
+
+void server_err()
+{
+ conoutf("server network error, disconnecting...");
+ disconnect();
+};
+
+int lastupdate = 0, lastping = 0;
+string toservermap;
+bool senditemstoserver = false; // after a map change, since server doesn't have map data
+
+string clientpassword;
+void password(char *p) { strcpy_s(clientpassword, p); };
+COMMAND(password, ARG_1STR);
+
+bool netmapstart() { senditemstoserver = true; return clienthost!=NULL; };
+
+void initclientnet()
+{
+ ctext[0] = 0;
+ toservermap[0] = 0;
+ clientpassword[0] = 0;
+ newname("unnamed");
+ newteam("red");
+};
+
+void sendpackettoserv(void *packet)
+{
+ if(clienthost) { enet_host_broadcast(clienthost, 0, (ENetPacket *)packet); enet_host_flush(clienthost); }
+ else localclienttoserver((ENetPacket *)packet);
+}
+
+void c2sinfo(dynent *d) // send update to the server
+{
+ if(clientnum<0) return; // we haven't had a welcome message from the server yet
+ if(lastmillis-lastupdate<40) return; // don't update faster than 25fps
+ ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ bool serveriteminitdone = false;
+ if(toservermap[0]) // suggest server to change map
+ { // do this exclusively as map change may invalidate rest of update
+ packet->flags = ENET_PACKET_FLAG_RELIABLE;
+ putint(p, SV_MAPCHANGE);
+ sendstring(toservermap, p);
+ toservermap[0] = 0;
+ putint(p, nextmode);
+ }
+ else
+ {
+ putint(p, SV_POS);
+ putint(p, clientnum);
+ putint(p, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes
+ putint(p, (int)(d->o.y*DMF));
+ putint(p, (int)(d->o.z*DMF));
+ putint(p, (int)(d->yaw*DAF));
+ putint(p, (int)(d->pitch*DAF));
+ putint(p, (int)(d->roll*DAF));
+ putint(p, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte
+ putint(p, (int)(d->vel.y*DVF));
+ putint(p, (int)(d->vel.z*DVF));
+ // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3
+ putint(p, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) );
+
+ if(senditemstoserver)
+ {
+ packet->flags = ENET_PACKET_FLAG_RELIABLE;
+ putint(p, SV_ITEMLIST);
+ if(!m_noitems) putitems(p);
+ putint(p, -1);
+ senditemstoserver = false;
+ serveriteminitdone = true;
+ };
+ if(ctext[0]) // player chat, not flood protected for now
+ {
+ packet->flags = ENET_PACKET_FLAG_RELIABLE;
+ putint(p, SV_TEXT);
+ sendstring(ctext, p);
+ ctext[0] = 0;
+ };
+ if(!c2sinit) // tell other clients who I am
+ {
+ packet->flags = ENET_PACKET_FLAG_RELIABLE;
+ c2sinit = true;
+ putint(p, SV_INITC2S);
+ sendstring(player1->name, p);
+ sendstring(player1->team, p);
+ putint(p, player1->lifesequence);
+ };
+ loopv(messages) // send messages collected during the previous frames
+ {
+ ivector &msg = messages[i];
+ if(msg[1]) packet->flags = ENET_PACKET_FLAG_RELIABLE;
+ loopi(msg[0]) putint(p, msg[i+2]);
+ };
+ messages.setsize(0);
+ if(lastmillis-lastping>250)
+ {
+ putint(p, SV_PING);
+ putint(p, lastmillis);
+ lastping = lastmillis;
+ };
+ };
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ incomingdemodata(start, p-start, true);
+ if(clienthost) { enet_host_broadcast(clienthost, 0, packet); enet_host_flush(clienthost); }
+ else localclienttoserver(packet);
+ lastupdate = lastmillis;
+ if(serveriteminitdone) loadgamerest(); // hack
+};
+
+void gets2c() // get updates from the server
+{
+ ENetEvent event;
+ if(!clienthost) return;
+ if(connecting && lastmillis/3000 > connecting/3000)
+ {
+ conoutf("attempting to connect...");
+ connecting = lastmillis;
+ ++connattempts;
+ if(connattempts > 3)
+ {
+ conoutf("could not connect to server");
+ disconnect();
+ return;
+ };
+ };
+ while(clienthost!=NULL && enet_host_service(clienthost, &event, 0)>0)
+ switch(event.type)
+ {
+ case ENET_EVENT_TYPE_CONNECT:
+ conoutf("connected to server");
+ connecting = 0;
+ throttle();
+ break;
+
+ case ENET_EVENT_TYPE_RECEIVE:
+ if(disconnecting) conoutf("attempting to disconnect...");
+ else localservertoclient(event.packet->data, event.packet->dataLength);
+ enet_packet_destroy(event.packet);
+ break;
+
+ case ENET_EVENT_TYPE_DISCONNECT:
+ if(disconnecting) disconnect();
+ else server_err();
+ return;
+ }
+};
+
DELETED src/clientextras.cpp
Index: src/clientextras.cpp
==================================================================
--- src/clientextras.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-// clientextras.cpp: stuff that didn't fit in client.cpp or clientgame.cpp :)
-
-#include "cube.h"
-
-// render players & monsters
-// very messy ad-hoc handling of animation frames, should be made more configurable
-
-// D D D D' D D D D' A A' P P' I I' R, R' E L J J'
-int frame[] = { 178, 184, 190, 137, 183, 189, 197, 164, 46, 51, 54, 32, 0, 0, 40, 1, 162, 162, 67, 168 };
-int range[] = { 6, 6, 8, 28, 1, 1, 1, 1, 8, 19, 4, 18, 40, 1, 6, 15, 1, 1, 1, 1 };
-
-void renderclient(dynent *d, bool team, char *mdlname, bool hellpig, float scale)
-{
- int n = 3;
- float speed = 100.0f;
- float mz = d->o.z-d->eyeheight+1.55f*scale;
- int basetime = -((int)d&0xFFF);
- if(d->state==CS_DEAD)
- {
- int r;
- if(hellpig) { n = 2; r = range[3]; } else { n = (int)d%3; r = range[n]; };
- basetime = d->lastaction;
- int t = lastmillis-d->lastaction;
- if(t<0 || t>20000) return;
- if(t>(r-1)*100) { n += 4; if(t>(r+10)*100) { t -= (r+10)*100; mz -= t*t/10000000000.0f*t; }; };
- if(mz<-1000) return;
- //mdl = (((int)d>>6)&1)+1;
- //mz = d->o.z-d->eyeheight+0.2f;
- //scale = 1.2f;
- }
- else if(d->state==CS_EDITING) { n = 16; }
- else if(d->state==CS_LAGGED) { n = 17; }
- else if(d->monsterstate==M_ATTACKING) { n = 8; }
- else if(d->monsterstate==M_PAIN) { n = 10; }
- else if((!d->move && !d->strafe) || !d->moving) { n = 12; }
- else if(!d->onfloor && d->timeinair>100) { n = 18; }
- else { n = 14; speed = 1200/d->maxspeed*scale; if(hellpig) speed = 300/d->maxspeed; };
- if(hellpig) { n++; scale *= 32; mz -= 1.9f; };
- rendermodel(mdlname, frame[n], range[n], 0, 1.5f, d->o.x, mz, d->o.y, d->yaw+90, d->pitch/2, team, scale, speed, 0, basetime);
-};
-
-extern int democlientnum;
-
-void renderclients()
-{
- dynent *d;
- loopv(players) if((d = players[i]) && (!demoplayback || i!=democlientnum)) renderclient(d, isteam(player1->team, d->team), "monster/ogro", false, 1.0f);
-};
-
-// creation of scoreboard pseudo-menu
-
-bool scoreson = false;
-
-void showscores(bool on)
-{
- scoreson = on;
- menuset(((int)on)-1);
-};
-
-struct sline { string s; };
-vector scorelines;
-
-void renderscore(dynent *d)
-{
- sprintf_sd(lag)("%d", d->plag);
- sprintf_sd(name) ("(%s)", d->name);
- sprintf_s(scorelines.add().s)("%d\t%s\t%d\t%s\t%s", d->frags, d->state==CS_LAGGED ? "LAG" : lag, d->ping, d->team, d->state==CS_DEAD ? name : d->name);
- menumanual(0, scorelines.length()-1, scorelines.last().s);
-};
-
-const int maxteams = 4;
-char *teamname[maxteams];
-int teamscore[maxteams], teamsused;
-string teamscores;
-int timeremain = 0;
-
-void addteamscore(dynent *d)
-{
- if(!d) return;
- loopi(teamsused) if(strcmp(teamname[i], d->team)==0) { teamscore[i] += d->frags; return; };
- if(teamsused==maxteams) return;
- teamname[teamsused] = d->team;
- teamscore[teamsused++] = d->frags;
-};
-
-void renderscores()
-{
- if(!scoreson) return;
- scorelines.setsize(0);
- if(!demoplayback) renderscore(player1);
- loopv(players) if(players[i]) renderscore(players[i]);
- sortmenu(0, scorelines.length());
- if(m_teammode)
- {
- teamsused = 0;
- loopv(players) addteamscore(players[i]);
- if(!demoplayback) addteamscore(player1);
- teamscores[0] = 0;
- loopj(teamsused)
- {
- sprintf_sd(sc)("[ %s: %d ]", teamname[j], teamscore[j]);
- strcat_s(teamscores, sc);
- };
- menumanual(0, scorelines.length(), "");
- menumanual(0, scorelines.length()+1, teamscores);
- };
-};
-
-// sendmap/getmap commands, should be replaced by more intuitive map downloading
-
-void sendmap(char *mapname)
-{
- if(*mapname) save_world(mapname);
- changemap(mapname);
- mapname = getclientmap();
- int mapsize;
- uchar *mapdata = readmap(mapname, &mapsize);
- if(!mapdata) return;
- ENetPacket *packet = enet_packet_create(NULL, MAXTRANS + mapsize, ENET_PACKET_FLAG_RELIABLE);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, SV_SENDMAP);
- sendstring(mapname, p);
- putint(p, mapsize);
- if(65535 - (p - start) < mapsize)
- {
- conoutf("map %s is too large to send", mapname);
- free(mapdata);
- enet_packet_destroy(packet);
- return;
- };
- memcpy(p, mapdata, mapsize);
- p += mapsize;
- free(mapdata);
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- sendpackettoserv(packet);
- conoutf("sending map %s to server...", mapname);
- sprintf_sd(msg)("[map %s uploaded to server, \"getmap\" to receive it]", mapname);
- toserver(msg);
-}
-
-void getmap()
-{
- ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, SV_RECVMAP);
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- sendpackettoserv(packet);
- conoutf("requesting map from server...");
-}
-
-COMMAND(sendmap, ARG_1STR);
-COMMAND(getmap, ARG_NONE);
-
ADDED src/clientextras.cxx
Index: src/clientextras.cxx
==================================================================
--- /dev/null
+++ src/clientextras.cxx
@@ -0,0 +1,157 @@
+// clientextras.cpp: stuff that didn't fit in client.cpp or clientgame.cpp :)
+
+#include "cube.h"
+
+// render players & monsters
+// very messy ad-hoc handling of animation frames, should be made more configurable
+
+// D D D D' D D D D' A A' P P' I I' R, R' E L J J'
+int frame[] = { 178, 184, 190, 137, 183, 189, 197, 164, 46, 51, 54, 32, 0, 0, 40, 1, 162, 162, 67, 168 };
+int range[] = { 6, 6, 8, 28, 1, 1, 1, 1, 8, 19, 4, 18, 40, 1, 6, 15, 1, 1, 1, 1 };
+
+void renderclient(dynent *d, bool team, char *mdlname, bool hellpig, float scale)
+{
+ int n = 3;
+ float speed = 100.0f;
+ float mz = d->o.z-d->eyeheight+1.55f*scale;
+ int basetime = -((int)d&0xFFF);
+ if(d->state==CS_DEAD)
+ {
+ int r;
+ if(hellpig) { n = 2; r = range[3]; } else { n = (int)d%3; r = range[n]; };
+ basetime = d->lastaction;
+ int t = lastmillis-d->lastaction;
+ if(t<0 || t>20000) return;
+ if(t>(r-1)*100) { n += 4; if(t>(r+10)*100) { t -= (r+10)*100; mz -= t*t/10000000000.0f*t; }; };
+ if(mz<-1000) return;
+ //mdl = (((int)d>>6)&1)+1;
+ //mz = d->o.z-d->eyeheight+0.2f;
+ //scale = 1.2f;
+ }
+ else if(d->state==CS_EDITING) { n = 16; }
+ else if(d->state==CS_LAGGED) { n = 17; }
+ else if(d->monsterstate==M_ATTACKING) { n = 8; }
+ else if(d->monsterstate==M_PAIN) { n = 10; }
+ else if((!d->move && !d->strafe) || !d->moving) { n = 12; }
+ else if(!d->onfloor && d->timeinair>100) { n = 18; }
+ else { n = 14; speed = 1200/d->maxspeed*scale; if(hellpig) speed = 300/d->maxspeed; };
+ if(hellpig) { n++; scale *= 32; mz -= 1.9f; };
+ rendermodel(mdlname, frame[n], range[n], 0, 1.5f, d->o.x, mz, d->o.y, d->yaw+90, d->pitch/2, team, scale, speed, 0, basetime);
+};
+
+extern int democlientnum;
+
+void renderclients()
+{
+ dynent *d;
+ loopv(players) if((d = players[i]) && (!demoplayback || i!=democlientnum)) renderclient(d, isteam(player1->team, d->team), "monster/ogro", false, 1.0f);
+};
+
+// creation of scoreboard pseudo-menu
+
+bool scoreson = false;
+
+void showscores(bool on)
+{
+ scoreson = on;
+ menuset(((int)on)-1);
+};
+
+struct sline { string s; };
+vector scorelines;
+
+void renderscore(dynent *d)
+{
+ sprintf_sd(lag)("%d", d->plag);
+ sprintf_sd(name) ("(%s)", d->name);
+ sprintf_s(scorelines.add().s)("%d\t%s\t%d\t%s\t%s", d->frags, d->state==CS_LAGGED ? "LAG" : lag, d->ping, d->team, d->state==CS_DEAD ? name : d->name);
+ menumanual(0, scorelines.length()-1, scorelines.last().s);
+};
+
+const int maxteams = 4;
+char *teamname[maxteams];
+int teamscore[maxteams], teamsused;
+string teamscores;
+int timeremain = 0;
+
+void addteamscore(dynent *d)
+{
+ if(!d) return;
+ loopi(teamsused) if(strcmp(teamname[i], d->team)==0) { teamscore[i] += d->frags; return; };
+ if(teamsused==maxteams) return;
+ teamname[teamsused] = d->team;
+ teamscore[teamsused++] = d->frags;
+};
+
+void renderscores()
+{
+ if(!scoreson) return;
+ scorelines.setsize(0);
+ if(!demoplayback) renderscore(player1);
+ loopv(players) if(players[i]) renderscore(players[i]);
+ sortmenu(0, scorelines.length());
+ if(m_teammode)
+ {
+ teamsused = 0;
+ loopv(players) addteamscore(players[i]);
+ if(!demoplayback) addteamscore(player1);
+ teamscores[0] = 0;
+ loopj(teamsused)
+ {
+ sprintf_sd(sc)("[ %s: %d ]", teamname[j], teamscore[j]);
+ strcat_s(teamscores, sc);
+ };
+ menumanual(0, scorelines.length(), "");
+ menumanual(0, scorelines.length()+1, teamscores);
+ };
+};
+
+// sendmap/getmap commands, should be replaced by more intuitive map downloading
+
+void sendmap(char *mapname)
+{
+ if(*mapname) save_world(mapname);
+ changemap(mapname);
+ mapname = getclientmap();
+ int mapsize;
+ uchar *mapdata = readmap(mapname, &mapsize);
+ if(!mapdata) return;
+ ENetPacket *packet = enet_packet_create(NULL, MAXTRANS + mapsize, ENET_PACKET_FLAG_RELIABLE);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, SV_SENDMAP);
+ sendstring(mapname, p);
+ putint(p, mapsize);
+ if(65535 - (p - start) < mapsize)
+ {
+ conoutf("map %s is too large to send", mapname);
+ free(mapdata);
+ enet_packet_destroy(packet);
+ return;
+ };
+ memcpy(p, mapdata, mapsize);
+ p += mapsize;
+ free(mapdata);
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ sendpackettoserv(packet);
+ conoutf("sending map %s to server...", mapname);
+ sprintf_sd(msg)("[map %s uploaded to server, \"getmap\" to receive it]", mapname);
+ toserver(msg);
+}
+
+void getmap()
+{
+ ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, SV_RECVMAP);
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ sendpackettoserv(packet);
+ conoutf("requesting map from server...");
+}
+
+COMMAND(sendmap, ARG_1STR);
+COMMAND(getmap, ARG_NONE);
+
DELETED src/clientgame.cpp
Index: src/clientgame.cpp
==================================================================
--- src/clientgame.cpp
+++ /dev/null
@@ -1,455 +0,0 @@
-// clientgame.cpp: core game related stuff
-
-#include "cube.h"
-
-int nextmode = 0; // nextmode becomes gamemode after next map load
-VAR(gamemode, 1, 0, 0);
-
-void mode(int n) { addmsg(1, 2, SV_GAMEMODE, nextmode = n); };
-COMMAND(mode, ARG_1INT);
-
-bool intermission = false;
-
-dynent *player1 = newdynent(); // our client
-dvector players; // other clients
-
-VARP(sensitivity, 0, 10, 10000);
-VARP(sensitivityscale, 1, 1, 10000);
-VARP(invmouse, 0, 0, 1);
-
-int lastmillis = 0;
-int curtime = 10;
-string clientmap;
-
-extern int framesinmap;
-
-char *getclientmap() { return clientmap; };
-
-void resetmovement(dynent *d)
-{
- d->k_left = false;
- d->k_right = false;
- d->k_up = false;
- d->k_down = false;
- d->jumpnext = false;
- d->strafe = 0;
- d->move = 0;
-};
-
-void spawnstate(dynent *d) // reset player state not persistent accross spawns
-{
- resetmovement(d);
- d->vel.x = d->vel.y = d->vel.z = 0;
- d->onfloor = false;
- d->timeinair = 0;
- d->health = 100;
- d->armour = 50;
- d->armourtype = A_BLUE;
- d->quadmillis = 0;
- d->lastattackgun = d->gunselect = GUN_SG;
- d->gunwait = 0;
- d->attacking = false;
- d->lastaction = 0;
- loopi(NUMGUNS) d->ammo[i] = 0;
- d->ammo[GUN_FIST] = 1;
- if(m_noitems)
- {
- d->gunselect = GUN_RIFLE;
- d->armour = 0;
- if(m_noitemsrail)
- {
- d->health = 1;
- d->ammo[GUN_RIFLE] = 100;
- }
- else
- {
- if(gamemode==12) { d->gunselect = GUN_FIST; return; }; // eihrul's secret "instafist" mode
- d->health = 256;
- if(m_tarena)
- {
- int gun1 = rnd(4)+1;
- baseammo(d->gunselect = gun1);
- for(;;)
- {
- int gun2 = rnd(4)+1;
- if(gun1!=gun2) { baseammo(gun2); break; };
- };
- }
- else if(m_arena) // insta arena
- {
- d->ammo[GUN_RIFLE] = 100;
- }
- else // efficiency
- {
- loopi(4) baseammo(i+1);
- d->gunselect = GUN_CG;
- };
- d->ammo[GUN_CG] /= 2;
- };
- }
- else
- {
- d->ammo[GUN_SG] = 5;
- };
-};
-
-dynent *newdynent() // create a new blank player or monster
-{
- dynent *d = (dynent *)gp()->alloc(sizeof(dynent));
- d->o.x = 0;
- d->o.y = 0;
- d->o.z = 0;
- d->yaw = 270;
- d->pitch = 0;
- d->roll = 0;
- d->maxspeed = 22;
- d->outsidemap = false;
- d->inwater = false;
- d->radius = 1.1f;
- d->eyeheight = 3.2f;
- d->aboveeye = 0.7f;
- d->frags = 0;
- d->plag = 0;
- d->ping = 0;
- d->lastupdate = lastmillis;
- d->enemy = NULL;
- d->monsterstate = 0;
- d->name[0] = d->team[0] = 0;
- d->blocked = false;
- d->lifesequence = 0;
- d->state = CS_ALIVE;
- spawnstate(d);
- return d;
-};
-
-void respawnself()
-{
- spawnplayer(player1);
- showscores(false);
-};
-
-void arenacount(dynent *d, int &alive, int &dead, char *&lastteam, bool &oneteam)
-{
- if(d->state!=CS_DEAD)
- {
- alive++;
- if(lastteam && strcmp(lastteam, d->team)) oneteam = false;
- lastteam = d->team;
- }
- else
- {
- dead++;
- };
-};
-
-int arenarespawnwait = 0;
-int arenadetectwait = 0;
-
-void arenarespawn()
-{
- if(arenarespawnwait)
- {
- if(arenarespawnwait0 && (alive<=1 || (m_teammode && oneteam)))
- {
- conoutf("arena round is over! next round in 5 seconds...");
- if(alive) conoutf("team %s is last man standing", lastteam);
- else conoutf("everyone died!");
- arenarespawnwait = lastmillis+5000;
- arenadetectwait = lastmillis+10000;
- player1->roll = 0;
- };
- };
-};
-
-void zapdynent(dynent *&d)
-{
- if(d) gp()->dealloc(d, sizeof(dynent));
- d = NULL;
-};
-
-extern int democlientnum;
-
-void otherplayers()
-{
- loopv(players) if(players[i])
- {
- const int lagtime = lastmillis-players[i]->lastupdate;
- if(lagtime>1000 && players[i]->state==CS_ALIVE)
- {
- players[i]->state = CS_LAGGED;
- continue;
- };
- if(lagtime && players[i]->state != CS_DEAD && (!demoplayback || i!=democlientnum)) moveplayer(players[i], 2, false); // use physics to extrapolate player position
- };
-};
-
-void respawn()
-{
- if(player1->state==CS_DEAD)
- {
- player1->attacking = false;
- if(m_arena) { conoutf("waiting for new round to start..."); return; };
- if(m_sp) { nextmode = gamemode; changemap(clientmap); return; }; // if we die in SP we try the same map again
- respawnself();
- };
-};
-
-int sleepwait = 0;
-string sleepcmd;
-void sleepf(char *msec, char *cmd) { sleepwait = atoi(msec)+lastmillis; strcpy_s(sleepcmd, cmd); };
-COMMANDN(sleep, sleepf, ARG_2STR);
-
-void updateworld(int millis) // main game update loop
-{
- if(lastmillis)
- {
- curtime = millis - lastmillis;
- if(sleepwait && lastmillis>sleepwait) { sleepwait = 0; execute(sleepcmd); };
- physicsframe();
- checkquad(curtime);
- if(m_arena) arenarespawn();
- moveprojectiles((float)curtime);
- demoplaybackstep();
- if(!demoplayback)
- {
- if(getclientnum()>=0) shoot(player1, worldpos); // only shoot when connected to server
- gets2c(); // do this first, so we have most accurate information when our player moves
- };
- otherplayers();
- if(!demoplayback)
- {
- monsterthink();
- if(player1->state==CS_DEAD)
- {
- if(lastmillis-player1->lastaction<2000)
- {
- player1->move = player1->strafe = 0;
- moveplayer(player1, 10, false);
- }
- else if(!m_arena && !m_sp && lastmillis-player1->lastaction>10000) respawn();
- }
- else if(!intermission)
- {
- moveplayer(player1, 20, true);
- checkitems();
- };
- c2sinfo(player1); // do this last, to reduce the effective frame lag
- };
- };
- lastmillis = millis;
-};
-
-void entinmap(dynent *d) // brute force but effective way to find a free spawn spot in the map
-{
- loopi(100) // try max 100 times
- {
- float dx = (rnd(21)-10)/10.0f*i; // increasing distance
- float dy = (rnd(21)-10)/10.0f*i;
- d->o.x += dx;
- d->o.y += dy;
- if(collide(d, true, 0, 0)) return;
- d->o.x -= dx;
- d->o.y -= dy;
- };
- conoutf("can't find entity spawn spot! (%d, %d)", (int)d->o.x, (int)d->o.y);
- // leave ent at original pos, possibly stuck
-};
-
-int spawncycle = -1;
-int fixspawn = 2;
-
-void spawnplayer(dynent *d) // place at random spawn. also used by monsters!
-{
- int r = fixspawn-->0 ? 4 : rnd(10)+1;
- loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1);
- if(spawncycle!=-1)
- {
- d->o.x = ents[spawncycle].x;
- d->o.y = ents[spawncycle].y;
- d->o.z = ents[spawncycle].z;
- d->yaw = ents[spawncycle].attr1;
- d->pitch = 0;
- d->roll = 0;
- }
- else
- {
- d->o.x = d->o.y = (float)ssize/2;
- d->o.z = 4;
- };
- entinmap(d);
- spawnstate(d);
- d->state = CS_ALIVE;
-};
-
-// movement input code
-
-#define dir(name,v,d,s,os) void name(bool isdown) { player1->s = isdown; player1->v = isdown ? d : (player1->os ? -(d) : 0); player1->lastmove = lastmillis; };
-
-dir(backward, move, -1, k_down, k_up);
-dir(forward, move, 1, k_up, k_down);
-dir(left, strafe, 1, k_left, k_right);
-dir(right, strafe, -1, k_right, k_left);
-
-void attack(bool on)
-{
- if(intermission) return;
- if(editmode) editdrag(on);
- else if(player1->attacking = on) respawn();
-};
-
-void jumpn(bool on) { if(!intermission && (player1->jumpnext = on)) respawn(); };
-
-COMMAND(backward, ARG_DOWN);
-COMMAND(forward, ARG_DOWN);
-COMMAND(left, ARG_DOWN);
-COMMAND(right, ARG_DOWN);
-COMMANDN(jump, jumpn, ARG_DOWN);
-COMMAND(attack, ARG_DOWN);
-COMMAND(showscores, ARG_DOWN);
-
-void fixplayer1range()
-{
- const float MAXPITCH = 90.0f;
- if(player1->pitch>MAXPITCH) player1->pitch = MAXPITCH;
- if(player1->pitch<-MAXPITCH) player1->pitch = -MAXPITCH;
- while(player1->yaw<0.0f) player1->yaw += 360.0f;
- while(player1->yaw>=360.0f) player1->yaw -= 360.0f;
-};
-
-void mousemove(int dx, int dy)
-{
- if(player1->state==CS_DEAD || intermission) return;
- const float SENSF = 33.0f; // try match quake sens
- player1->yaw += (dx/SENSF)*(sensitivity/(float)sensitivityscale);
- player1->pitch -= (dy/SENSF)*(sensitivity/(float)sensitivityscale)*(invmouse ? -1 : 1);
- fixplayer1range();
-};
-
-// damage arriving from the network, monsters, yourself, all ends up here.
-
-void selfdamage(int damage, int actor, dynent *act)
-{
- if(player1->state!=CS_ALIVE || editmode || intermission) return;
- damageblend(damage);
- demoblend(damage);
- int ad = damage*(player1->armourtype+1)*20/100; // let armour absorb when possible
- if(ad>player1->armour) ad = player1->armour;
- player1->armour -= ad;
- damage -= ad;
- float droll = damage/0.5f;
- player1->roll += player1->roll>0 ? droll : (player1->roll<0 ? -droll : (rnd(2) ? droll : -droll)); // give player a kick depending on amount of damage
- if((player1->health -= damage)<=0)
- {
- if(actor==-2)
- {
- conoutf("you got killed by %s!", act->name);
- }
- else if(actor==-1)
- {
- actor = getclientnum();
- conoutf("you suicided!");
- addmsg(1, 2, SV_FRAGS, --player1->frags);
- }
- else
- {
- dynent *a = getclient(actor);
- if(a)
- {
- if(isteam(a->team, player1->team))
- {
- conoutf("you got fragged by a teammate (%s)", a->name);
- }
- else
- {
- conoutf("you got fragged by %s", a->name);
- };
- };
- };
- showscores(true);
- addmsg(1, 2, SV_DIED, actor);
- player1->lifesequence++;
- player1->attacking = false;
- player1->state = CS_DEAD;
- player1->pitch = 0;
- player1->roll = 60;
- playsound(S_DIE1+rnd(2));
- spawnstate(player1);
- player1->lastaction = lastmillis;
- }
- else
- {
- playsound(S_PAIN6);
- };
-};
-
-void timeupdate(int timeremain)
-{
- if(!timeremain)
- {
- intermission = true;
- player1->attacking = false;
- conoutf("intermission:");
- conoutf("game has ended!");
- showscores(true);
- }
- else
- {
- conoutf("time remaining: %d minutes", timeremain);
- };
-};
-
-dynent *getclient(int cn) // ensure valid entity
-{
- if(cn<0 || cn>=MAXCLIENTS)
- {
- neterr("clientnum");
- return NULL;
- };
- while(cn>=players.length()) players.add(NULL);
- return players[cn] ? players[cn] : (players[cn] = newdynent());
-};
-
-void initclient()
-{
- clientmap[0] = 0;
- initclientnet();
-};
-
-void startmap(char *name) // called just after a map load
-{
- if(netmapstart() && m_sp) { gamemode = 0; conoutf("coop sp not supported yet"); };
- sleepwait = 0;
- monsterclear();
- projreset();
- spawncycle = -1;
- spawnplayer(player1);
- player1->frags = 0;
- loopv(players) if(players[i]) players[i]->frags = 0;
- resetspawns();
- strcpy_s(clientmap, name);
- if(editmode) toggleedit();
- setvar("gamespeed", 100);
- setvar("fog", 180);
- setvar("fogcolour", 0x8099B3);
- showscores(false);
- intermission = false;
- framesinmap = 0;
- conoutf("game mode is %s", modestr(gamemode));
-};
-
-COMMANDN(map, changemap, ARG_1STR);
ADDED src/clientgame.cxx
Index: src/clientgame.cxx
==================================================================
--- /dev/null
+++ src/clientgame.cxx
@@ -0,0 +1,455 @@
+// clientgame.cpp: core game related stuff
+
+#include "cube.h"
+
+int nextmode = 0; // nextmode becomes gamemode after next map load
+VAR(gamemode, 1, 0, 0);
+
+void mode(int n) { addmsg(1, 2, SV_GAMEMODE, nextmode = n); };
+COMMAND(mode, ARG_1INT);
+
+bool intermission = false;
+
+dynent *player1 = newdynent(); // our client
+dvector players; // other clients
+
+VARP(sensitivity, 0, 10, 10000);
+VARP(sensitivityscale, 1, 1, 10000);
+VARP(invmouse, 0, 0, 1);
+
+int lastmillis = 0;
+int curtime = 10;
+string clientmap;
+
+extern int framesinmap;
+
+char *getclientmap() { return clientmap; };
+
+void resetmovement(dynent *d)
+{
+ d->k_left = false;
+ d->k_right = false;
+ d->k_up = false;
+ d->k_down = false;
+ d->jumpnext = false;
+ d->strafe = 0;
+ d->move = 0;
+};
+
+void spawnstate(dynent *d) // reset player state not persistent accross spawns
+{
+ resetmovement(d);
+ d->vel.x = d->vel.y = d->vel.z = 0;
+ d->onfloor = false;
+ d->timeinair = 0;
+ d->health = 100;
+ d->armour = 50;
+ d->armourtype = A_BLUE;
+ d->quadmillis = 0;
+ d->lastattackgun = d->gunselect = GUN_SG;
+ d->gunwait = 0;
+ d->attacking = false;
+ d->lastaction = 0;
+ loopi(NUMGUNS) d->ammo[i] = 0;
+ d->ammo[GUN_FIST] = 1;
+ if(m_noitems)
+ {
+ d->gunselect = GUN_RIFLE;
+ d->armour = 0;
+ if(m_noitemsrail)
+ {
+ d->health = 1;
+ d->ammo[GUN_RIFLE] = 100;
+ }
+ else
+ {
+ if(gamemode==12) { d->gunselect = GUN_FIST; return; }; // eihrul's secret "instafist" mode
+ d->health = 256;
+ if(m_tarena)
+ {
+ int gun1 = rnd(4)+1;
+ baseammo(d->gunselect = gun1);
+ for(;;)
+ {
+ int gun2 = rnd(4)+1;
+ if(gun1!=gun2) { baseammo(gun2); break; };
+ };
+ }
+ else if(m_arena) // insta arena
+ {
+ d->ammo[GUN_RIFLE] = 100;
+ }
+ else // efficiency
+ {
+ loopi(4) baseammo(i+1);
+ d->gunselect = GUN_CG;
+ };
+ d->ammo[GUN_CG] /= 2;
+ };
+ }
+ else
+ {
+ d->ammo[GUN_SG] = 5;
+ };
+};
+
+dynent *newdynent() // create a new blank player or monster
+{
+ dynent *d = (dynent *)gp()->alloc(sizeof(dynent));
+ d->o.x = 0;
+ d->o.y = 0;
+ d->o.z = 0;
+ d->yaw = 270;
+ d->pitch = 0;
+ d->roll = 0;
+ d->maxspeed = 22;
+ d->outsidemap = false;
+ d->inwater = false;
+ d->radius = 1.1f;
+ d->eyeheight = 3.2f;
+ d->aboveeye = 0.7f;
+ d->frags = 0;
+ d->plag = 0;
+ d->ping = 0;
+ d->lastupdate = lastmillis;
+ d->enemy = NULL;
+ d->monsterstate = 0;
+ d->name[0] = d->team[0] = 0;
+ d->blocked = false;
+ d->lifesequence = 0;
+ d->state = CS_ALIVE;
+ spawnstate(d);
+ return d;
+};
+
+void respawnself()
+{
+ spawnplayer(player1);
+ showscores(false);
+};
+
+void arenacount(dynent *d, int &alive, int &dead, char *&lastteam, bool &oneteam)
+{
+ if(d->state!=CS_DEAD)
+ {
+ alive++;
+ if(lastteam && strcmp(lastteam, d->team)) oneteam = false;
+ lastteam = d->team;
+ }
+ else
+ {
+ dead++;
+ };
+};
+
+int arenarespawnwait = 0;
+int arenadetectwait = 0;
+
+void arenarespawn()
+{
+ if(arenarespawnwait)
+ {
+ if(arenarespawnwait0 && (alive<=1 || (m_teammode && oneteam)))
+ {
+ conoutf("arena round is over! next round in 5 seconds...");
+ if(alive) conoutf("team %s is last man standing", lastteam);
+ else conoutf("everyone died!");
+ arenarespawnwait = lastmillis+5000;
+ arenadetectwait = lastmillis+10000;
+ player1->roll = 0;
+ };
+ };
+};
+
+void zapdynent(dynent *&d)
+{
+ if(d) gp()->dealloc(d, sizeof(dynent));
+ d = NULL;
+};
+
+extern int democlientnum;
+
+void otherplayers()
+{
+ loopv(players) if(players[i])
+ {
+ const int lagtime = lastmillis-players[i]->lastupdate;
+ if(lagtime>1000 && players[i]->state==CS_ALIVE)
+ {
+ players[i]->state = CS_LAGGED;
+ continue;
+ };
+ if(lagtime && players[i]->state != CS_DEAD && (!demoplayback || i!=democlientnum)) moveplayer(players[i], 2, false); // use physics to extrapolate player position
+ };
+};
+
+void respawn()
+{
+ if(player1->state==CS_DEAD)
+ {
+ player1->attacking = false;
+ if(m_arena) { conoutf("waiting for new round to start..."); return; };
+ if(m_sp) { nextmode = gamemode; changemap(clientmap); return; }; // if we die in SP we try the same map again
+ respawnself();
+ };
+};
+
+int sleepwait = 0;
+string sleepcmd;
+void sleepf(char *msec, char *cmd) { sleepwait = atoi(msec)+lastmillis; strcpy_s(sleepcmd, cmd); };
+COMMANDN(sleep, sleepf, ARG_2STR);
+
+void updateworld(int millis) // main game update loop
+{
+ if(lastmillis)
+ {
+ curtime = millis - lastmillis;
+ if(sleepwait && lastmillis>sleepwait) { sleepwait = 0; execute(sleepcmd); };
+ physicsframe();
+ checkquad(curtime);
+ if(m_arena) arenarespawn();
+ moveprojectiles((float)curtime);
+ demoplaybackstep();
+ if(!demoplayback)
+ {
+ if(getclientnum()>=0) shoot(player1, worldpos); // only shoot when connected to server
+ gets2c(); // do this first, so we have most accurate information when our player moves
+ };
+ otherplayers();
+ if(!demoplayback)
+ {
+ monsterthink();
+ if(player1->state==CS_DEAD)
+ {
+ if(lastmillis-player1->lastaction<2000)
+ {
+ player1->move = player1->strafe = 0;
+ moveplayer(player1, 10, false);
+ }
+ else if(!m_arena && !m_sp && lastmillis-player1->lastaction>10000) respawn();
+ }
+ else if(!intermission)
+ {
+ moveplayer(player1, 20, true);
+ checkitems();
+ };
+ c2sinfo(player1); // do this last, to reduce the effective frame lag
+ };
+ };
+ lastmillis = millis;
+};
+
+void entinmap(dynent *d) // brute force but effective way to find a free spawn spot in the map
+{
+ loopi(100) // try max 100 times
+ {
+ float dx = (rnd(21)-10)/10.0f*i; // increasing distance
+ float dy = (rnd(21)-10)/10.0f*i;
+ d->o.x += dx;
+ d->o.y += dy;
+ if(collide(d, true, 0, 0)) return;
+ d->o.x -= dx;
+ d->o.y -= dy;
+ };
+ conoutf("can't find entity spawn spot! (%d, %d)", (int)d->o.x, (int)d->o.y);
+ // leave ent at original pos, possibly stuck
+};
+
+int spawncycle = -1;
+int fixspawn = 2;
+
+void spawnplayer(dynent *d) // place at random spawn. also used by monsters!
+{
+ int r = fixspawn-->0 ? 4 : rnd(10)+1;
+ loopi(r) spawncycle = findentity(PLAYERSTART, spawncycle+1);
+ if(spawncycle!=-1)
+ {
+ d->o.x = ents[spawncycle].x;
+ d->o.y = ents[spawncycle].y;
+ d->o.z = ents[spawncycle].z;
+ d->yaw = ents[spawncycle].attr1;
+ d->pitch = 0;
+ d->roll = 0;
+ }
+ else
+ {
+ d->o.x = d->o.y = (float)ssize/2;
+ d->o.z = 4;
+ };
+ entinmap(d);
+ spawnstate(d);
+ d->state = CS_ALIVE;
+};
+
+// movement input code
+
+#define dir(name,v,d,s,os) void name(bool isdown) { player1->s = isdown; player1->v = isdown ? d : (player1->os ? -(d) : 0); player1->lastmove = lastmillis; };
+
+dir(backward, move, -1, k_down, k_up);
+dir(forward, move, 1, k_up, k_down);
+dir(left, strafe, 1, k_left, k_right);
+dir(right, strafe, -1, k_right, k_left);
+
+void attack(bool on)
+{
+ if(intermission) return;
+ if(editmode) editdrag(on);
+ else if(player1->attacking = on) respawn();
+};
+
+void jumpn(bool on) { if(!intermission && (player1->jumpnext = on)) respawn(); };
+
+COMMAND(backward, ARG_DOWN);
+COMMAND(forward, ARG_DOWN);
+COMMAND(left, ARG_DOWN);
+COMMAND(right, ARG_DOWN);
+COMMANDN(jump, jumpn, ARG_DOWN);
+COMMAND(attack, ARG_DOWN);
+COMMAND(showscores, ARG_DOWN);
+
+void fixplayer1range()
+{
+ const float MAXPITCH = 90.0f;
+ if(player1->pitch>MAXPITCH) player1->pitch = MAXPITCH;
+ if(player1->pitch<-MAXPITCH) player1->pitch = -MAXPITCH;
+ while(player1->yaw<0.0f) player1->yaw += 360.0f;
+ while(player1->yaw>=360.0f) player1->yaw -= 360.0f;
+};
+
+void mousemove(int dx, int dy)
+{
+ if(player1->state==CS_DEAD || intermission) return;
+ const float SENSF = 33.0f; // try match quake sens
+ player1->yaw += (dx/SENSF)*(sensitivity/(float)sensitivityscale);
+ player1->pitch -= (dy/SENSF)*(sensitivity/(float)sensitivityscale)*(invmouse ? -1 : 1);
+ fixplayer1range();
+};
+
+// damage arriving from the network, monsters, yourself, all ends up here.
+
+void selfdamage(int damage, int actor, dynent *act)
+{
+ if(player1->state!=CS_ALIVE || editmode || intermission) return;
+ damageblend(damage);
+ demoblend(damage);
+ int ad = damage*(player1->armourtype+1)*20/100; // let armour absorb when possible
+ if(ad>player1->armour) ad = player1->armour;
+ player1->armour -= ad;
+ damage -= ad;
+ float droll = damage/0.5f;
+ player1->roll += player1->roll>0 ? droll : (player1->roll<0 ? -droll : (rnd(2) ? droll : -droll)); // give player a kick depending on amount of damage
+ if((player1->health -= damage)<=0)
+ {
+ if(actor==-2)
+ {
+ conoutf("you got killed by %s!", act->name);
+ }
+ else if(actor==-1)
+ {
+ actor = getclientnum();
+ conoutf("you suicided!");
+ addmsg(1, 2, SV_FRAGS, --player1->frags);
+ }
+ else
+ {
+ dynent *a = getclient(actor);
+ if(a)
+ {
+ if(isteam(a->team, player1->team))
+ {
+ conoutf("you got fragged by a teammate (%s)", a->name);
+ }
+ else
+ {
+ conoutf("you got fragged by %s", a->name);
+ };
+ };
+ };
+ showscores(true);
+ addmsg(1, 2, SV_DIED, actor);
+ player1->lifesequence++;
+ player1->attacking = false;
+ player1->state = CS_DEAD;
+ player1->pitch = 0;
+ player1->roll = 60;
+ playsound(S_DIE1+rnd(2));
+ spawnstate(player1);
+ player1->lastaction = lastmillis;
+ }
+ else
+ {
+ playsound(S_PAIN6);
+ };
+};
+
+void timeupdate(int timeremain)
+{
+ if(!timeremain)
+ {
+ intermission = true;
+ player1->attacking = false;
+ conoutf("intermission:");
+ conoutf("game has ended!");
+ showscores(true);
+ }
+ else
+ {
+ conoutf("time remaining: %d minutes", timeremain);
+ };
+};
+
+dynent *getclient(int cn) // ensure valid entity
+{
+ if(cn<0 || cn>=MAXCLIENTS)
+ {
+ neterr("clientnum");
+ return NULL;
+ };
+ while(cn>=players.length()) players.add(NULL);
+ return players[cn] ? players[cn] : (players[cn] = newdynent());
+};
+
+void initclient()
+{
+ clientmap[0] = 0;
+ initclientnet();
+};
+
+void startmap(char *name) // called just after a map load
+{
+ if(netmapstart() && m_sp) { gamemode = 0; conoutf("coop sp not supported yet"); };
+ sleepwait = 0;
+ monsterclear();
+ projreset();
+ spawncycle = -1;
+ spawnplayer(player1);
+ player1->frags = 0;
+ loopv(players) if(players[i]) players[i]->frags = 0;
+ resetspawns();
+ strcpy_s(clientmap, name);
+ if(editmode) toggleedit();
+ setvar("gamespeed", 100);
+ setvar("fog", 180);
+ setvar("fogcolour", 0x8099B3);
+ showscores(false);
+ intermission = false;
+ framesinmap = 0;
+ conoutf("game mode is %s", modestr(gamemode));
+};
+
+COMMANDN(map, changemap, ARG_1STR);
DELETED src/clients2c.cpp
Index: src/clients2c.cpp
==================================================================
--- src/clients2c.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-// client processing of the incoming network stream
-
-#include "cube.h"
-
-extern int clientnum;
-extern bool c2sinit, senditemstoserver;
-extern string toservermap;
-extern string clientpassword;
-
-void neterr(char *s)
-{
- conoutf("illegal network message (%s)", s);
- disconnect();
-};
-
-void changemapserv(char *name, int mode) // forced map change from the server
-{
- gamemode = mode;
- load_world(name);
-};
-
-void changemap(char *name) // request map change, server may ignore
-{
- strcpy_s(toservermap, name);
-};
-
-// update the position of other clients in the game in our world
-// don't care if he's in the scenery or other players,
-// just don't overlap with our client
-
-void updatepos(dynent *d)
-{
- const float r = player1->radius+d->radius;
- const float dx = player1->o.x-d->o.x;
- const float dy = player1->o.y-d->o.y;
- const float dz = player1->o.z-d->o.z;
- const float rz = player1->aboveeye+d->eyeheight;
- const float fx = (float)fabs(dx), fy = (float)fabs(dy), fz = (float)fabs(dz);
- if(fxstate!=CS_DEAD)
- {
- if(fxo.y += dy<0 ? r-fy : -(r-fy); // push aside
- else d->o.x += dx<0 ? r-fx : -(r-fx);
- };
- int lagtime = lastmillis-d->lastupdate;
- if(lagtime)
- {
- d->plag = (d->plag*5+lagtime)/6;
- d->lastupdate = lastmillis;
- };
-};
-
-void localservertoclient(uchar *buf, int len) // processes any updates from the server
-{
- if(ENET_NET_TO_HOST_16(*(ushort *)buf)!=len) neterr("packet length");
- incomingdemodata(buf, len);
-
- uchar *end = buf+len;
- uchar *p = buf+2;
- char text[MAXTRANS];
- int cn = -1, type;
- dynent *d = NULL;
- bool mapchanged = false;
-
- while(po.x = getint(p)/DMF;
- d->o.y = getint(p)/DMF;
- d->o.z = getint(p)/DMF;
- d->yaw = getint(p)/DAF;
- d->pitch = getint(p)/DAF;
- d->roll = getint(p)/DAF;
- d->vel.x = getint(p)/DVF;
- d->vel.y = getint(p)/DVF;
- d->vel.z = getint(p)/DVF;
- int f = getint(p);
- d->strafe = (f&3)==3 ? -1 : f&3;
- f >>= 2;
- d->move = (f&3)==3 ? -1 : f&3;
- d->onfloor = (f>>2)&1;
- int state = f>>3;
- if(state==CS_DEAD && d->state!=CS_DEAD) d->lastaction = lastmillis;
- d->state = state;
- if(!demoplayback) updatepos(d);
- break;
- };
-
- case SV_SOUND:
- playsound(getint(p), &d->o);
- break;
-
- case SV_TEXT:
- sgetstr();
- conoutf("%s:\f %s", d->name, text);
- break;
-
- case SV_MAPCHANGE:
- sgetstr();
- changemapserv(text, getint(p));
- mapchanged = true;
- break;
-
- case SV_ITEMLIST:
- {
- int n;
- if(mapchanged) { senditemstoserver = false; resetspawns(); };
- while((n = getint(p))!=-1) if(mapchanged) setspawn(n, true);
- break;
- };
-
- case SV_MAPRELOAD: // server requests next map
- {
- getint(p);
- sprintf_sd(nextmapalias)("nextmap_%s", getclientmap());
- char *map = getalias(nextmapalias); // look up map in the cycle
- changemap(map ? map : getclientmap());
- break;
- };
-
- case SV_INITC2S: // another client either connected or changed name/team
- {
- sgetstr();
- if(d->name[0]) // already connected
- {
- if(strcmp(d->name, text))
- conoutf("%s is now known as %s", d->name, text);
- }
- else // new client
- {
- c2sinit = false; // send new players my info again
- conoutf("connected: %s", text);
- };
- strcpy_s(d->name, text);
- sgetstr();
- strcpy_s(d->team, text);
- d->lifesequence = getint(p);
- break;
- };
-
- case SV_CDIS:
- cn = getint(p);
- if(!(d = getclient(cn))) break;
- conoutf("player %s disconnected", d->name[0] ? d->name : "[incompatible client]");
- zapdynent(players[cn]);
- break;
-
- case SV_SHOT:
- {
- int gun = getint(p);
- vec s, e;
- s.x = getint(p)/DMF;
- s.y = getint(p)/DMF;
- s.z = getint(p)/DMF;
- e.x = getint(p)/DMF;
- e.y = getint(p)/DMF;
- e.z = getint(p)/DMF;
- if(gun==GUN_SG) createrays(s, e);
- shootv(gun, s, e, d);
- break;
- };
-
- case SV_DAMAGE:
- {
- int target = getint(p);
- int damage = getint(p);
- int ls = getint(p);
- if(target==clientnum) { if(ls==player1->lifesequence) selfdamage(damage, cn, d); }
- else playsound(S_PAIN1+rnd(5), &getclient(target)->o);
- break;
- };
-
- case SV_DIED:
- {
- int actor = getint(p);
- if(actor==cn)
- {
- conoutf("%s suicided", d->name);
- }
- else if(actor==clientnum)
- {
- int frags;
- if(isteam(player1->team, d->team))
- {
- frags = -1;
- conoutf("you fragged a teammate (%s)", d->name);
- }
- else
- {
- frags = 1;
- conoutf("you fragged %s", d->name);
- };
- addmsg(1, 2, SV_FRAGS, player1->frags += frags);
- }
- else
- {
- dynent *a = getclient(actor);
- if(a)
- {
- if(isteam(a->team, d->name))
- {
- conoutf("%s fragged his teammate (%s)", a->name, d->name);
- }
- else
- {
- conoutf("%s fragged %s", a->name, d->name);
- };
- };
- };
- playsound(S_DIE1+rnd(2), &d->o);
- d->lifesequence++;
- break;
- };
-
- case SV_FRAGS:
- players[cn]->frags = getint(p);
- break;
-
- case SV_ITEMPICKUP:
- setspawn(getint(p), false);
- getint(p);
- break;
-
- case SV_ITEMSPAWN:
- {
- uint i = getint(p);
- setspawn(i, true);
- if(i>=(uint)ents.length()) break;
- vec v = { ents[i].x, ents[i].y, ents[i].z };
- playsound(S_ITEMSPAWN, &v);
- break;
- };
-
- case SV_ITEMACC: // server acknowledges that I picked up this item
- realpickup(getint(p), player1);
- break;
-
- case SV_EDITH: // coop editing messages, should be extended to include all possible editing ops
- case SV_EDITT:
- case SV_EDITS:
- case SV_EDITD:
- case SV_EDITE:
- {
- int x = getint(p);
- int y = getint(p);
- int xs = getint(p);
- int ys = getint(p);
- int v = getint(p);
- block b = { x, y, xs, ys };
- switch(type)
- {
- case SV_EDITH: editheightxy(v!=0, getint(p), b); break;
- case SV_EDITT: edittexxy(v, getint(p), b); break;
- case SV_EDITS: edittypexy(v, b); break;
- case SV_EDITD: setvdeltaxy(v, b); break;
- case SV_EDITE: editequalisexy(v!=0, b); break;
- };
- break;
- };
-
- case SV_EDITENT: // coop edit of ent
- {
- uint i = getint(p);
- while((uint)ents.length()<=i) ents.add().type = NOTUSED;
- int to = ents[i].type;
- ents[i].type = getint(p);
- ents[i].x = getint(p);
- ents[i].y = getint(p);
- ents[i].z = getint(p);
- ents[i].attr1 = getint(p);
- ents[i].attr2 = getint(p);
- ents[i].attr3 = getint(p);
- ents[i].attr4 = getint(p);
- ents[i].spawned = false;
- if(ents[i].type==LIGHT || to==LIGHT) calclight();
- break;
- };
-
- case SV_PING:
- getint(p);
- break;
-
- case SV_PONG:
- addmsg(0, 2, SV_CLIENTPING, player1->ping = (player1->ping*5+lastmillis-getint(p))/6);
- break;
-
- case SV_CLIENTPING:
- players[cn]->ping = getint(p);
- break;
-
- case SV_GAMEMODE:
- nextmode = getint(p);
- break;
-
- case SV_TIMEUP:
- timeupdate(getint(p));
- break;
-
- case SV_RECVMAP:
- {
- sgetstr();
- conoutf("received map \"%s\" from server, reloading..", text);
- int mapsize = getint(p);
- writemap(text, mapsize, p);
- p += mapsize;
- changemapserv(text, gamemode);
- break;
- };
-
- case SV_SERVMSG:
- sgetstr();
- conoutf("%s", text);
- break;
-
- case SV_EXT: // so we can messages without breaking previous clients/servers, if necessary
- {
- for(int n = getint(p); n; n--) getint(p);
- break;
- };
-
- default:
- neterr("type");
- return;
- };
-};
ADDED src/clients2c.cxx
Index: src/clients2c.cxx
==================================================================
--- /dev/null
+++ src/clients2c.cxx
@@ -0,0 +1,355 @@
+// client processing of the incoming network stream
+
+#include "cube.h"
+
+extern int clientnum;
+extern bool c2sinit, senditemstoserver;
+extern string toservermap;
+extern string clientpassword;
+
+void neterr(char *s)
+{
+ conoutf("illegal network message (%s)", s);
+ disconnect();
+};
+
+void changemapserv(char *name, int mode) // forced map change from the server
+{
+ gamemode = mode;
+ load_world(name);
+};
+
+void changemap(char *name) // request map change, server may ignore
+{
+ strcpy_s(toservermap, name);
+};
+
+// update the position of other clients in the game in our world
+// don't care if he's in the scenery or other players,
+// just don't overlap with our client
+
+void updatepos(dynent *d)
+{
+ const float r = player1->radius+d->radius;
+ const float dx = player1->o.x-d->o.x;
+ const float dy = player1->o.y-d->o.y;
+ const float dz = player1->o.z-d->o.z;
+ const float rz = player1->aboveeye+d->eyeheight;
+ const float fx = (float)fabs(dx), fy = (float)fabs(dy), fz = (float)fabs(dz);
+ if(fxstate!=CS_DEAD)
+ {
+ if(fxo.y += dy<0 ? r-fy : -(r-fy); // push aside
+ else d->o.x += dx<0 ? r-fx : -(r-fx);
+ };
+ int lagtime = lastmillis-d->lastupdate;
+ if(lagtime)
+ {
+ d->plag = (d->plag*5+lagtime)/6;
+ d->lastupdate = lastmillis;
+ };
+};
+
+void localservertoclient(uchar *buf, int len) // processes any updates from the server
+{
+ if(ENET_NET_TO_HOST_16(*(ushort *)buf)!=len) neterr("packet length");
+ incomingdemodata(buf, len);
+
+ uchar *end = buf+len;
+ uchar *p = buf+2;
+ char text[MAXTRANS];
+ int cn = -1, type;
+ dynent *d = NULL;
+ bool mapchanged = false;
+
+ while(po.x = getint(p)/DMF;
+ d->o.y = getint(p)/DMF;
+ d->o.z = getint(p)/DMF;
+ d->yaw = getint(p)/DAF;
+ d->pitch = getint(p)/DAF;
+ d->roll = getint(p)/DAF;
+ d->vel.x = getint(p)/DVF;
+ d->vel.y = getint(p)/DVF;
+ d->vel.z = getint(p)/DVF;
+ int f = getint(p);
+ d->strafe = (f&3)==3 ? -1 : f&3;
+ f >>= 2;
+ d->move = (f&3)==3 ? -1 : f&3;
+ d->onfloor = (f>>2)&1;
+ int state = f>>3;
+ if(state==CS_DEAD && d->state!=CS_DEAD) d->lastaction = lastmillis;
+ d->state = state;
+ if(!demoplayback) updatepos(d);
+ break;
+ };
+
+ case SV_SOUND:
+ playsound(getint(p), &d->o);
+ break;
+
+ case SV_TEXT:
+ sgetstr();
+ conoutf("%s:\f %s", d->name, text);
+ break;
+
+ case SV_MAPCHANGE:
+ sgetstr();
+ changemapserv(text, getint(p));
+ mapchanged = true;
+ break;
+
+ case SV_ITEMLIST:
+ {
+ int n;
+ if(mapchanged) { senditemstoserver = false; resetspawns(); };
+ while((n = getint(p))!=-1) if(mapchanged) setspawn(n, true);
+ break;
+ };
+
+ case SV_MAPRELOAD: // server requests next map
+ {
+ getint(p);
+ sprintf_sd(nextmapalias)("nextmap_%s", getclientmap());
+ char *map = getalias(nextmapalias); // look up map in the cycle
+ changemap(map ? map : getclientmap());
+ break;
+ };
+
+ case SV_INITC2S: // another client either connected or changed name/team
+ {
+ sgetstr();
+ if(d->name[0]) // already connected
+ {
+ if(strcmp(d->name, text))
+ conoutf("%s is now known as %s", d->name, text);
+ }
+ else // new client
+ {
+ c2sinit = false; // send new players my info again
+ conoutf("connected: %s", text);
+ };
+ strcpy_s(d->name, text);
+ sgetstr();
+ strcpy_s(d->team, text);
+ d->lifesequence = getint(p);
+ break;
+ };
+
+ case SV_CDIS:
+ cn = getint(p);
+ if(!(d = getclient(cn))) break;
+ conoutf("player %s disconnected", d->name[0] ? d->name : "[incompatible client]");
+ zapdynent(players[cn]);
+ break;
+
+ case SV_SHOT:
+ {
+ int gun = getint(p);
+ vec s, e;
+ s.x = getint(p)/DMF;
+ s.y = getint(p)/DMF;
+ s.z = getint(p)/DMF;
+ e.x = getint(p)/DMF;
+ e.y = getint(p)/DMF;
+ e.z = getint(p)/DMF;
+ if(gun==GUN_SG) createrays(s, e);
+ shootv(gun, s, e, d);
+ break;
+ };
+
+ case SV_DAMAGE:
+ {
+ int target = getint(p);
+ int damage = getint(p);
+ int ls = getint(p);
+ if(target==clientnum) { if(ls==player1->lifesequence) selfdamage(damage, cn, d); }
+ else playsound(S_PAIN1+rnd(5), &getclient(target)->o);
+ break;
+ };
+
+ case SV_DIED:
+ {
+ int actor = getint(p);
+ if(actor==cn)
+ {
+ conoutf("%s suicided", d->name);
+ }
+ else if(actor==clientnum)
+ {
+ int frags;
+ if(isteam(player1->team, d->team))
+ {
+ frags = -1;
+ conoutf("you fragged a teammate (%s)", d->name);
+ }
+ else
+ {
+ frags = 1;
+ conoutf("you fragged %s", d->name);
+ };
+ addmsg(1, 2, SV_FRAGS, player1->frags += frags);
+ }
+ else
+ {
+ dynent *a = getclient(actor);
+ if(a)
+ {
+ if(isteam(a->team, d->name))
+ {
+ conoutf("%s fragged his teammate (%s)", a->name, d->name);
+ }
+ else
+ {
+ conoutf("%s fragged %s", a->name, d->name);
+ };
+ };
+ };
+ playsound(S_DIE1+rnd(2), &d->o);
+ d->lifesequence++;
+ break;
+ };
+
+ case SV_FRAGS:
+ players[cn]->frags = getint(p);
+ break;
+
+ case SV_ITEMPICKUP:
+ setspawn(getint(p), false);
+ getint(p);
+ break;
+
+ case SV_ITEMSPAWN:
+ {
+ uint i = getint(p);
+ setspawn(i, true);
+ if(i>=(uint)ents.length()) break;
+ vec v = { ents[i].x, ents[i].y, ents[i].z };
+ playsound(S_ITEMSPAWN, &v);
+ break;
+ };
+
+ case SV_ITEMACC: // server acknowledges that I picked up this item
+ realpickup(getint(p), player1);
+ break;
+
+ case SV_EDITH: // coop editing messages, should be extended to include all possible editing ops
+ case SV_EDITT:
+ case SV_EDITS:
+ case SV_EDITD:
+ case SV_EDITE:
+ {
+ int x = getint(p);
+ int y = getint(p);
+ int xs = getint(p);
+ int ys = getint(p);
+ int v = getint(p);
+ block b = { x, y, xs, ys };
+ switch(type)
+ {
+ case SV_EDITH: editheightxy(v!=0, getint(p), b); break;
+ case SV_EDITT: edittexxy(v, getint(p), b); break;
+ case SV_EDITS: edittypexy(v, b); break;
+ case SV_EDITD: setvdeltaxy(v, b); break;
+ case SV_EDITE: editequalisexy(v!=0, b); break;
+ };
+ break;
+ };
+
+ case SV_EDITENT: // coop edit of ent
+ {
+ uint i = getint(p);
+ while((uint)ents.length()<=i) ents.add().type = NOTUSED;
+ int to = ents[i].type;
+ ents[i].type = getint(p);
+ ents[i].x = getint(p);
+ ents[i].y = getint(p);
+ ents[i].z = getint(p);
+ ents[i].attr1 = getint(p);
+ ents[i].attr2 = getint(p);
+ ents[i].attr3 = getint(p);
+ ents[i].attr4 = getint(p);
+ ents[i].spawned = false;
+ if(ents[i].type==LIGHT || to==LIGHT) calclight();
+ break;
+ };
+
+ case SV_PING:
+ getint(p);
+ break;
+
+ case SV_PONG:
+ addmsg(0, 2, SV_CLIENTPING, player1->ping = (player1->ping*5+lastmillis-getint(p))/6);
+ break;
+
+ case SV_CLIENTPING:
+ players[cn]->ping = getint(p);
+ break;
+
+ case SV_GAMEMODE:
+ nextmode = getint(p);
+ break;
+
+ case SV_TIMEUP:
+ timeupdate(getint(p));
+ break;
+
+ case SV_RECVMAP:
+ {
+ sgetstr();
+ conoutf("received map \"%s\" from server, reloading..", text);
+ int mapsize = getint(p);
+ writemap(text, mapsize, p);
+ p += mapsize;
+ changemapserv(text, gamemode);
+ break;
+ };
+
+ case SV_SERVMSG:
+ sgetstr();
+ conoutf("%s", text);
+ break;
+
+ case SV_EXT: // so we can messages without breaking previous clients/servers, if necessary
+ {
+ for(int n = getint(p); n; n--) getint(p);
+ break;
+ };
+
+ default:
+ neterr("type");
+ return;
+ };
+};
DELETED src/command.cpp
Index: src/command.cpp
==================================================================
--- src/command.cpp
+++ /dev/null
@@ -1,363 +0,0 @@
-// command.cpp: implements the parsing and execution of a tiny script language which
-// is largely backwards compatible with the quake console language.
-
-#include "cube.h"
-
-enum { ID_VAR, ID_COMMAND, ID_ALIAS };
-
-struct ident
-{
- int type; // one of ID_* above
- char *name;
- int min, max; // ID_VAR
- int *storage; // ID_VAR
- void (*fun)(); // ID_VAR, ID_COMMAND
- int narg; // ID_VAR, ID_COMMAND
- char *action; // ID_ALIAS
- bool persist;
-};
-
-void itoa(char *s, int i) { sprintf_s(s)("%d", i); };
-char *exchangestr(char *o, char *n) { gp()->deallocstr(o); return newstring(n); };
-
-hashtable *idents = NULL; // contains ALL vars/commands/aliases
-
-void alias(char *name, char *action)
-{
- ident *b = idents->access(name);
- if(!b)
- {
- name = newstring(name);
- ident b = { ID_ALIAS, name, 0, 0, 0, 0, 0, newstring(action), true };
- idents->access(name, &b);
- }
- else
- {
- if(b->type==ID_ALIAS) b->action = exchangestr(b->action, action);
- else conoutf("cannot redefine builtin %s with an alias", name);
- };
-};
-
-COMMAND(alias, ARG_2STR);
-
-// variable's and commands are registered through globals, see cube.h
-
-int variable(char *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist)
-{
- if(!idents) idents = new hashtable;
- ident v = { ID_VAR, name, min, max, storage, fun, 0, 0, persist };
- idents->access(name, &v);
- return cur;
-};
-
-void setvar(char *name, int i) { *idents->access(name)->storage = i; };
-int getvar(char *name) { return *idents->access(name)->storage; };
-bool identexists(char *name) { return idents->access(name)!=NULL; };
-
-char *getalias(char *name)
-{
- ident *i = idents->access(name);
- return i && i->type==ID_ALIAS ? i->action : NULL;
-};
-
-bool addcommand(char *name, void (*fun)(), int narg)
-{
- if(!idents) idents = new hashtable;
- ident c = { ID_COMMAND, name, 0, 0, 0, fun, narg, 0, false };
- idents->access(name, &c);
- return false;
-};
-
-char *parseexp(char *&p, int right) // parse any nested set of () or []
-{
- int left = *p++;
- char *word = p;
- for(int brak = 1; brak; )
- {
- int c = *p++;
- if(c=='\r') *(p-1) = ' '; // hack
- if(c==left) brak++;
- else if(c==right) brak--;
- else if(!c) { p--; conoutf("missing \"%c\"", right); return NULL; };
- };
- char *s = newstring(word, p-word-1);
- if(left=='(')
- {
- string t;
- itoa(t, execute(s)); // evaluate () exps directly, and substitute result
- s = exchangestr(s, t);
- };
- return s;
-};
-
-char *parseword(char *&p) // parse single argument, including expressions
-{
- p += strspn(p, " \t\r");
- if(p[0]=='/' && p[1]=='/') p += strcspn(p, "\n\0");
- if(*p=='\"')
- {
- p++;
- char *word = p;
- p += strcspn(p, "\"\r\n\0");
- char *s = newstring(word, p-word);
- if(*p=='\"') p++;
- return s;
- };
- if(*p=='(') return parseexp(p, ')');
- if(*p=='[') return parseexp(p, ']');
- char *word = p;
- p += strcspn(p, "; \t\r\n\0");
- if(p-word==0) return NULL;
- return newstring(word, p-word);
-};
-
-char *lookup(char *n) // find value of ident referenced with $ in exp
-{
- ident *id = idents->access(n+1);
- if(id) switch(id->type)
- {
- case ID_VAR: string t; itoa(t, *(id->storage)); return exchangestr(n, t);
- case ID_ALIAS: return exchangestr(n, id->action);
- };
- conoutf("unknown alias lookup: %s", n+1);
- return n;
-};
-
-int execute(char *p, bool isdown) // all evaluation happens here, recursively
-{
- const int MAXWORDS = 25; // limit, remove
- char *w[MAXWORDS];
- int val = 0;
- for(bool cont = true; cont;) // for each ; seperated statement
- {
- int numargs = MAXWORDS;
- loopi(MAXWORDS) // collect all argument values
- {
- w[i] = "";
- if(i>numargs) continue;
- char *s = parseword(p); // parse and evaluate exps
- if(!s) { numargs = i; s = ""; };
- if(*s=='$') s = lookup(s); // substitute variables
- w[i] = s;
- };
-
- p += strcspn(p, ";\n\0");
- cont = *p++!=0; // more statements if this isn't the end of the string
- char *c = w[0];
- if(*c=='/') c++; // strip irc-style command prefix
- if(!*c) continue; // empty statement
-
- ident *id = idents->access(c);
- if(!id)
- {
- val = ATOI(c);
- if(!val && *c!='0') conoutf("unknown command: %s", c);
- }
- else switch(id->type)
- {
- case ID_COMMAND: // game defined commands
- switch(id->narg) // use very ad-hoc function signature, and just call it
- {
- case ARG_1INT: if(isdown) ((void (__cdecl *)(int))id->fun)(ATOI(w[1])); break;
- case ARG_2INT: if(isdown) ((void (__cdecl *)(int, int))id->fun)(ATOI(w[1]), ATOI(w[2])); break;
- case ARG_3INT: if(isdown) ((void (__cdecl *)(int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3])); break;
- case ARG_4INT: if(isdown) ((void (__cdecl *)(int, int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3]), ATOI(w[4])); break;
- case ARG_NONE: if(isdown) ((void (__cdecl *)())id->fun)(); break;
- case ARG_1STR: if(isdown) ((void (__cdecl *)(char *))id->fun)(w[1]); break;
- case ARG_2STR: if(isdown) ((void (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break;
- case ARG_3STR: if(isdown) ((void (__cdecl *)(char *, char *, char*))id->fun)(w[1], w[2], w[3]); break;
- case ARG_5STR: if(isdown) ((void (__cdecl *)(char *, char *, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5]); break;
- case ARG_DOWN: ((void (__cdecl *)(bool))id->fun)(isdown); break;
- case ARG_DWN1: ((void (__cdecl *)(bool, char *))id->fun)(isdown, w[1]); break;
- case ARG_1EXP: if(isdown) val = ((int (__cdecl *)(int))id->fun)(execute(w[1])); break;
- case ARG_2EXP: if(isdown) val = ((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2])); break;
- case ARG_1EST: if(isdown) val = ((int (__cdecl *)(char *))id->fun)(w[1]); break;
- case ARG_2EST: if(isdown) val = ((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break;
- case ARG_VARI: if(isdown)
- {
- string r; // limit, remove
- r[0] = 0;
- for(int i = 1; ifun)(r);
- break;
- }
- };
- break;
-
- case ID_VAR: // game defined variabled
- if(isdown)
- {
- if(!w[1][0]) conoutf("%s = %d", c, *id->storage); // var with no value just prints its current value
- else
- {
- if(id->min>id->max)
- {
- conoutf("variable is read-only");
- }
- else
- {
- int i1 = ATOI(w[1]);
- if(i1min || i1>id->max)
- {
- i1 = i1min ? id->min : id->max; // clamp to valid range
- conoutf("valid range for %s is %d..%d", c, id->min, id->max);
- }
- *id->storage = i1;
- };
- if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available
- };
- };
- break;
-
- case ID_ALIAS: // alias, also used as functions and (global) variables
- for(int i = 1; iaction); // create new string here because alias could rebind itself
- val = execute(action, isdown);
- gp()->deallocstr(action);
- break;
- };
- loopj(numargs) gp()->deallocstr(w[j]);
- };
- return val;
-};
-
-// tab-completion of all idents
-
-int completesize = 0, completeidx = 0;
-
-void resetcomplete() { completesize = 0; };
-
-void complete(char *s)
-{
- if(*s!='/')
- {
- string t;
- strcpy_s(t, s);
- strcpy_s(s, "/");
- strcat_s(s, t);
- };
- if(!s[1]) return;
- if(!completesize) { completesize = (int)strlen(s)-1; completeidx = 0; };
- int idx = 0;
- enumerate(idents, ident *, id,
- if(strncmp(id->name, s+1, completesize)==0 && idx++==completeidx)
- {
- strcpy_s(s, "/");
- strcat_s(s, id->name);
- };
- );
- completeidx++;
- if(completeidx>=idx) completeidx = 0;
-};
-
-bool execfile(char *cfgfile)
-{
- string s;
- strcpy_s(s, cfgfile);
- char *buf = loadfile(path(s), NULL);
- if(!buf) return false;
- execute(buf);
- free(buf);
- return true;
-};
-
-void exec(char *cfgfile)
-{
- if(!execfile(cfgfile)) conoutf("could not read \"%s\"", cfgfile);
-};
-
-void writecfg()
-{
- FILE *f = fopen("config.cfg", "w");
- if(!f) return;
- fprintf(f, "// automatically written on exit, do not modify\n// delete this file to have defaults.cfg overwrite these settings\n// modify settings in game, or put settings in autoexec.cfg to override anything\n\n");
- writeclientinfo(f);
- fprintf(f, "\n");
- enumerate(idents, ident *, id,
- if(id->type==ID_VAR && id->persist)
- {
- fprintf(f, "%s %d\n", id->name, *id->storage);
- };
- );
- fprintf(f, "\n");
- writebinds(f);
- fprintf(f, "\n");
- enumerate(idents, ident *, id,
- if(id->type==ID_ALIAS && !strstr(id->name, "nextmap_"))
- {
- fprintf(f, "alias \"%s\" [%s]\n", id->name, id->action);
- };
- );
- fclose(f);
-};
-
-COMMAND(writecfg, ARG_NONE);
-
-// below the commands that implement a small imperative language. thanks to the semantics of
-// () and [] expressions, any control construct can be defined trivially.
-
-void intset(char *name, int v) { string b; itoa(b, v); alias(name, b); };
-
-void ifthen(char *cond, char *thenp, char *elsep) { execute(cond[0]!='0' ? thenp : elsep); };
-void loopa(char *times, char *body) { int t = atoi(times); loopi(t) { intset("i", i); execute(body); }; };
-void whilea(char *cond, char *body) { while(execute(cond)) execute(body); }; // can't get any simpler than this :)
-void onrelease(bool on, char *body) { if(!on) execute(body); };
-
-void concat(char *s) { alias("s", s); };
-
-void concatword(char *s)
-{
- for(char *a = s, *b = s; *a = *b; b++) if(*a!=' ') a++;
- concat(s);
-};
-
-int listlen(char *a)
-{
- if(!*a) return 0;
- int n = 0;
- while(*a) if(*a++==' ') n++;
- return n+1;
-};
-
-void at(char *s, char *pos)
-{
- int n = atoi(pos);
- loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
- s[strcspn(s, " \0")] = 0;
- concat(s);
-};
-
-COMMANDN(loop, loopa, ARG_2STR);
-COMMANDN(while, whilea, ARG_2STR);
-COMMANDN(if, ifthen, ARG_3STR);
-COMMAND(onrelease, ARG_DWN1);
-COMMAND(exec, ARG_1STR);
-COMMAND(concat, ARG_VARI);
-COMMAND(concatword, ARG_VARI);
-COMMAND(at, ARG_2STR);
-COMMAND(listlen, ARG_1EST);
-
-int add(int a, int b) { return a+b; }; COMMANDN(+, add, ARG_2EXP);
-int mul(int a, int b) { return a*b; }; COMMANDN(*, mul, ARG_2EXP);
-int sub(int a, int b) { return a-b; }; COMMANDN(-, sub, ARG_2EXP);
-int divi(int a, int b) { return b ? a/b : 0; }; COMMANDN(div, divi, ARG_2EXP);
-int mod(int a, int b) { return b ? a%b : 0; }; COMMAND(mod, ARG_2EXP);
-int equal(int a, int b) { return (int)(a==b); }; COMMANDN(=, equal, ARG_2EXP);
-int lt(int a, int b) { return (int)(ab); }; COMMANDN(>, gt, ARG_2EXP);
-
-int strcmpa(char *a, char *b) { return strcmp(a,b)==0; }; COMMANDN(strcmp, strcmpa, ARG_2EST);
-
-int rndn(int a) { return a>0 ? rnd(a) : 0; }; COMMANDN(rnd, rndn, ARG_1EXP);
-
-int explastmillis() { return lastmillis; }; COMMANDN(millis, explastmillis, ARG_1EXP);
-
ADDED src/command.cxx
Index: src/command.cxx
==================================================================
--- /dev/null
+++ src/command.cxx
@@ -0,0 +1,363 @@
+// command.cpp: implements the parsing and execution of a tiny script language which
+// is largely backwards compatible with the quake console language.
+
+#include "cube.h"
+
+enum { ID_VAR, ID_COMMAND, ID_ALIAS };
+
+struct ident
+{
+ int type; // one of ID_* above
+ char *name;
+ int min, max; // ID_VAR
+ int *storage; // ID_VAR
+ void (*fun)(); // ID_VAR, ID_COMMAND
+ int narg; // ID_VAR, ID_COMMAND
+ char *action; // ID_ALIAS
+ bool persist;
+};
+
+void itoa(char *s, int i) { sprintf_s(s)("%d", i); };
+char *exchangestr(char *o, char *n) { gp()->deallocstr(o); return newstring(n); };
+
+hashtable *idents = NULL; // contains ALL vars/commands/aliases
+
+void alias(char *name, char *action)
+{
+ ident *b = idents->access(name);
+ if(!b)
+ {
+ name = newstring(name);
+ ident b = { ID_ALIAS, name, 0, 0, 0, 0, 0, newstring(action), true };
+ idents->access(name, &b);
+ }
+ else
+ {
+ if(b->type==ID_ALIAS) b->action = exchangestr(b->action, action);
+ else conoutf("cannot redefine builtin %s with an alias", name);
+ };
+};
+
+COMMAND(alias, ARG_2STR);
+
+// variable's and commands are registered through globals, see cube.h
+
+int variable(char *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist)
+{
+ if(!idents) idents = new hashtable;
+ ident v = { ID_VAR, name, min, max, storage, fun, 0, 0, persist };
+ idents->access(name, &v);
+ return cur;
+};
+
+void setvar(char *name, int i) { *idents->access(name)->storage = i; };
+int getvar(char *name) { return *idents->access(name)->storage; };
+bool identexists(char *name) { return idents->access(name)!=NULL; };
+
+char *getalias(char *name)
+{
+ ident *i = idents->access(name);
+ return i && i->type==ID_ALIAS ? i->action : NULL;
+};
+
+bool addcommand(char *name, void (*fun)(), int narg)
+{
+ if(!idents) idents = new hashtable;
+ ident c = { ID_COMMAND, name, 0, 0, 0, fun, narg, 0, false };
+ idents->access(name, &c);
+ return false;
+};
+
+char *parseexp(char *&p, int right) // parse any nested set of () or []
+{
+ int left = *p++;
+ char *word = p;
+ for(int brak = 1; brak; )
+ {
+ int c = *p++;
+ if(c=='\r') *(p-1) = ' '; // hack
+ if(c==left) brak++;
+ else if(c==right) brak--;
+ else if(!c) { p--; conoutf("missing \"%c\"", right); return NULL; };
+ };
+ char *s = newstring(word, p-word-1);
+ if(left=='(')
+ {
+ string t;
+ itoa(t, execute(s)); // evaluate () exps directly, and substitute result
+ s = exchangestr(s, t);
+ };
+ return s;
+};
+
+char *parseword(char *&p) // parse single argument, including expressions
+{
+ p += strspn(p, " \t\r");
+ if(p[0]=='/' && p[1]=='/') p += strcspn(p, "\n\0");
+ if(*p=='\"')
+ {
+ p++;
+ char *word = p;
+ p += strcspn(p, "\"\r\n\0");
+ char *s = newstring(word, p-word);
+ if(*p=='\"') p++;
+ return s;
+ };
+ if(*p=='(') return parseexp(p, ')');
+ if(*p=='[') return parseexp(p, ']');
+ char *word = p;
+ p += strcspn(p, "; \t\r\n\0");
+ if(p-word==0) return NULL;
+ return newstring(word, p-word);
+};
+
+char *lookup(char *n) // find value of ident referenced with $ in exp
+{
+ ident *id = idents->access(n+1);
+ if(id) switch(id->type)
+ {
+ case ID_VAR: string t; itoa(t, *(id->storage)); return exchangestr(n, t);
+ case ID_ALIAS: return exchangestr(n, id->action);
+ };
+ conoutf("unknown alias lookup: %s", n+1);
+ return n;
+};
+
+int execute(char *p, bool isdown) // all evaluation happens here, recursively
+{
+ const int MAXWORDS = 25; // limit, remove
+ char *w[MAXWORDS];
+ int val = 0;
+ for(bool cont = true; cont;) // for each ; seperated statement
+ {
+ int numargs = MAXWORDS;
+ loopi(MAXWORDS) // collect all argument values
+ {
+ w[i] = "";
+ if(i>numargs) continue;
+ char *s = parseword(p); // parse and evaluate exps
+ if(!s) { numargs = i; s = ""; };
+ if(*s=='$') s = lookup(s); // substitute variables
+ w[i] = s;
+ };
+
+ p += strcspn(p, ";\n\0");
+ cont = *p++!=0; // more statements if this isn't the end of the string
+ char *c = w[0];
+ if(*c=='/') c++; // strip irc-style command prefix
+ if(!*c) continue; // empty statement
+
+ ident *id = idents->access(c);
+ if(!id)
+ {
+ val = ATOI(c);
+ if(!val && *c!='0') conoutf("unknown command: %s", c);
+ }
+ else switch(id->type)
+ {
+ case ID_COMMAND: // game defined commands
+ switch(id->narg) // use very ad-hoc function signature, and just call it
+ {
+ case ARG_1INT: if(isdown) ((void (__cdecl *)(int))id->fun)(ATOI(w[1])); break;
+ case ARG_2INT: if(isdown) ((void (__cdecl *)(int, int))id->fun)(ATOI(w[1]), ATOI(w[2])); break;
+ case ARG_3INT: if(isdown) ((void (__cdecl *)(int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3])); break;
+ case ARG_4INT: if(isdown) ((void (__cdecl *)(int, int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3]), ATOI(w[4])); break;
+ case ARG_NONE: if(isdown) ((void (__cdecl *)())id->fun)(); break;
+ case ARG_1STR: if(isdown) ((void (__cdecl *)(char *))id->fun)(w[1]); break;
+ case ARG_2STR: if(isdown) ((void (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break;
+ case ARG_3STR: if(isdown) ((void (__cdecl *)(char *, char *, char*))id->fun)(w[1], w[2], w[3]); break;
+ case ARG_5STR: if(isdown) ((void (__cdecl *)(char *, char *, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5]); break;
+ case ARG_DOWN: ((void (__cdecl *)(bool))id->fun)(isdown); break;
+ case ARG_DWN1: ((void (__cdecl *)(bool, char *))id->fun)(isdown, w[1]); break;
+ case ARG_1EXP: if(isdown) val = ((int (__cdecl *)(int))id->fun)(execute(w[1])); break;
+ case ARG_2EXP: if(isdown) val = ((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2])); break;
+ case ARG_1EST: if(isdown) val = ((int (__cdecl *)(char *))id->fun)(w[1]); break;
+ case ARG_2EST: if(isdown) val = ((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break;
+ case ARG_VARI: if(isdown)
+ {
+ string r; // limit, remove
+ r[0] = 0;
+ for(int i = 1; ifun)(r);
+ break;
+ }
+ };
+ break;
+
+ case ID_VAR: // game defined variabled
+ if(isdown)
+ {
+ if(!w[1][0]) conoutf("%s = %d", c, *id->storage); // var with no value just prints its current value
+ else
+ {
+ if(id->min>id->max)
+ {
+ conoutf("variable is read-only");
+ }
+ else
+ {
+ int i1 = ATOI(w[1]);
+ if(i1min || i1>id->max)
+ {
+ i1 = i1min ? id->min : id->max; // clamp to valid range
+ conoutf("valid range for %s is %d..%d", c, id->min, id->max);
+ }
+ *id->storage = i1;
+ };
+ if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available
+ };
+ };
+ break;
+
+ case ID_ALIAS: // alias, also used as functions and (global) variables
+ for(int i = 1; iaction); // create new string here because alias could rebind itself
+ val = execute(action, isdown);
+ gp()->deallocstr(action);
+ break;
+ };
+ loopj(numargs) gp()->deallocstr(w[j]);
+ };
+ return val;
+};
+
+// tab-completion of all idents
+
+int completesize = 0, completeidx = 0;
+
+void resetcomplete() { completesize = 0; };
+
+void complete(char *s)
+{
+ if(*s!='/')
+ {
+ string t;
+ strcpy_s(t, s);
+ strcpy_s(s, "/");
+ strcat_s(s, t);
+ };
+ if(!s[1]) return;
+ if(!completesize) { completesize = (int)strlen(s)-1; completeidx = 0; };
+ int idx = 0;
+ enumerate(idents, ident *, id,
+ if(strncmp(id->name, s+1, completesize)==0 && idx++==completeidx)
+ {
+ strcpy_s(s, "/");
+ strcat_s(s, id->name);
+ };
+ );
+ completeidx++;
+ if(completeidx>=idx) completeidx = 0;
+};
+
+bool execfile(char *cfgfile)
+{
+ string s;
+ strcpy_s(s, cfgfile);
+ char *buf = loadfile(path(s), NULL);
+ if(!buf) return false;
+ execute(buf);
+ free(buf);
+ return true;
+};
+
+void exec(char *cfgfile)
+{
+ if(!execfile(cfgfile)) conoutf("could not read \"%s\"", cfgfile);
+};
+
+void writecfg()
+{
+ FILE *f = fopen("config.cfg", "w");
+ if(!f) return;
+ fprintf(f, "// automatically written on exit, do not modify\n// delete this file to have defaults.cfg overwrite these settings\n// modify settings in game, or put settings in autoexec.cfg to override anything\n\n");
+ writeclientinfo(f);
+ fprintf(f, "\n");
+ enumerate(idents, ident *, id,
+ if(id->type==ID_VAR && id->persist)
+ {
+ fprintf(f, "%s %d\n", id->name, *id->storage);
+ };
+ );
+ fprintf(f, "\n");
+ writebinds(f);
+ fprintf(f, "\n");
+ enumerate(idents, ident *, id,
+ if(id->type==ID_ALIAS && !strstr(id->name, "nextmap_"))
+ {
+ fprintf(f, "alias \"%s\" [%s]\n", id->name, id->action);
+ };
+ );
+ fclose(f);
+};
+
+COMMAND(writecfg, ARG_NONE);
+
+// below the commands that implement a small imperative language. thanks to the semantics of
+// () and [] expressions, any control construct can be defined trivially.
+
+void intset(char *name, int v) { string b; itoa(b, v); alias(name, b); };
+
+void ifthen(char *cond, char *thenp, char *elsep) { execute(cond[0]!='0' ? thenp : elsep); };
+void loopa(char *times, char *body) { int t = atoi(times); loopi(t) { intset("i", i); execute(body); }; };
+void whilea(char *cond, char *body) { while(execute(cond)) execute(body); }; // can't get any simpler than this :)
+void onrelease(bool on, char *body) { if(!on) execute(body); };
+
+void concat(char *s) { alias("s", s); };
+
+void concatword(char *s)
+{
+ for(char *a = s, *b = s; *a = *b; b++) if(*a!=' ') a++;
+ concat(s);
+};
+
+int listlen(char *a)
+{
+ if(!*a) return 0;
+ int n = 0;
+ while(*a) if(*a++==' ') n++;
+ return n+1;
+};
+
+void at(char *s, char *pos)
+{
+ int n = atoi(pos);
+ loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
+ s[strcspn(s, " \0")] = 0;
+ concat(s);
+};
+
+COMMANDN(loop, loopa, ARG_2STR);
+COMMANDN(while, whilea, ARG_2STR);
+COMMANDN(if, ifthen, ARG_3STR);
+COMMAND(onrelease, ARG_DWN1);
+COMMAND(exec, ARG_1STR);
+COMMAND(concat, ARG_VARI);
+COMMAND(concatword, ARG_VARI);
+COMMAND(at, ARG_2STR);
+COMMAND(listlen, ARG_1EST);
+
+int add(int a, int b) { return a+b; }; COMMANDN(+, add, ARG_2EXP);
+int mul(int a, int b) { return a*b; }; COMMANDN(*, mul, ARG_2EXP);
+int sub(int a, int b) { return a-b; }; COMMANDN(-, sub, ARG_2EXP);
+int divi(int a, int b) { return b ? a/b : 0; }; COMMANDN(div, divi, ARG_2EXP);
+int mod(int a, int b) { return b ? a%b : 0; }; COMMAND(mod, ARG_2EXP);
+int equal(int a, int b) { return (int)(a==b); }; COMMANDN(=, equal, ARG_2EXP);
+int lt(int a, int b) { return (int)(ab); }; COMMANDN(>, gt, ARG_2EXP);
+
+int strcmpa(char *a, char *b) { return strcmp(a,b)==0; }; COMMANDN(strcmp, strcmpa, ARG_2EST);
+
+int rndn(int a) { return a>0 ? rnd(a) : 0; }; COMMANDN(rnd, rndn, ARG_1EXP);
+
+int explastmillis() { return lastmillis; }; COMMANDN(millis, explastmillis, ARG_1EXP);
+
DELETED src/console.cpp
Index: src/console.cpp
==================================================================
--- src/console.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-// console.cpp: the console buffer, its display, and command line control
-
-#include "cube.h"
-#include
-
-struct cline { char *cref; int outtime; };
-vector conlines;
-
-const int ndraw = 5;
-const int WORDWRAP = 80;
-int conskip = 0;
-
-bool saycommandon = false;
-string commandbuf;
-
-void setconskip(int n)
-{
- conskip += n;
- if(conskip<0) conskip = 0;
-};
-
-COMMANDN(conskip, setconskip, ARG_1INT);
-
-void conline(const char *sf, bool highlight) // add a line to the console buffer
-{
- cline cl;
- cl.cref = conlines.length()>100 ? conlines.pop().cref : newstringbuf(""); // constrain the buffer size
- cl.outtime = lastmillis; // for how long to keep line on screen
- conlines.insert(0,cl);
- if(highlight) // show line in a different colour, for chat etc.
- {
- cl.cref[0] = '\f';
- cl.cref[1] = 0;
- strcat_s(cl.cref, sf);
- }
- else
- {
- strcpy_s(cl.cref, sf);
- };
- puts(cl.cref);
- #ifndef WIN32
- fflush(stdout);
- #endif
-};
-
-void conoutf(const char *s, ...)
-{
- sprintf_sdv(sf, s);
- s = sf;
- int n = 0;
- while(strlen(s)>WORDWRAP) // cut strings to fit on screen
- {
- string t;
- strn0cpy(t, s, WORDWRAP+1);
- conline(t, n++!=0);
- s += WORDWRAP;
- };
- conline(s, n!=0);
-};
-
-void renderconsole() // render buffer taking into account time & scrolling
-{
- int nd = 0;
- char *refs[ndraw];
- loopv(conlines) if(conskip ? i>=conskip-1 || i>=conlines.length()-ndraw : lastmillis-conlines[i].outtime<20000)
- {
- refs[nd++] = conlines[i].cref;
- if(nd==ndraw) break;
- };
- loopj(nd)
- {
- draw_text(refs[j], FONTH/3, (FONTH/4*5)*(nd-j-1)+FONTH/3, 2);
- };
-};
-
-// keymap is defined externally in keymap.cfg
-
-struct keym { int code; char *name; char *action; } keyms[256];
-int numkm = 0;
-
-void keymap(char *code, char *key, char *action)
-{
- keyms[numkm].code = atoi(code);
- keyms[numkm].name = newstring(key);
- keyms[numkm++].action = newstringbuf(action);
-};
-
-COMMAND(keymap, ARG_3STR);
-
-void bindkey(char *key, char *action)
-{
- for(char *x = key; *x; x++) *x = toupper(*x);
- loopi(numkm) if(strcmp(keyms[i].name, key)==0)
- {
- strcpy_s(keyms[i].action, action);
- return;
- };
- conoutf("unknown key \"%s\"", key);
-};
-
-COMMANDN(bind, bindkey, ARG_2STR);
-
-void saycommand(char *init) // turns input to the command line on or off
-{
- SDL_EnableUNICODE(saycommandon = (init!=NULL));
- if(!editmode) keyrepeat(saycommandon);
- if(!init) init = "";
- strcpy_s(commandbuf, init);
-};
-
-void mapmsg(char *s) { strn0cpy(hdr.maptitle, s, 128); };
-
-COMMAND(saycommand, ARG_VARI);
-COMMAND(mapmsg, ARG_1STR);
-
-#ifndef WIN32
-#include
-#include
-#endif
-
-void pasteconsole()
-{
- #ifdef WIN32
- if(!IsClipboardFormatAvailable(CF_TEXT)) return;
- if(!OpenClipboard(NULL)) return;
- char *cb = (char *)GlobalLock(GetClipboardData(CF_TEXT));
- strcat_s(commandbuf, cb);
- GlobalUnlock(cb);
- CloseClipboard();
- #else
- SDL_SysWMinfo wminfo;
- SDL_VERSION(&wminfo.version);
- wminfo.subsystem = SDL_SYSWM_X11;
- if(!SDL_GetWMInfo(&wminfo)) return;
- int cbsize;
- char *cb = XFetchBytes(wminfo.info.x11.display, &cbsize);
- if(!cb || !cbsize) return;
- int commandlen = strlen(commandbuf);
- for(char *cbline = cb, *cbend; commandlen + 1 < _MAXDEFSTR && cbline < &cb[cbsize]; cbline = cbend + 1)
- {
- cbend = (char *)memchr(cbline, '\0', &cb[cbsize] - cbline);
- if(!cbend) cbend = &cb[cbsize];
- if(commandlen + cbend - cbline + 1 > _MAXDEFSTR) cbend = cbline + _MAXDEFSTR - commandlen - 1;
- memcpy(&commandbuf[commandlen], cbline, cbend - cbline);
- commandlen += cbend - cbline;
- commandbuf[commandlen] = '\n';
- if(commandlen + 1 < _MAXDEFSTR && cbend < &cb[cbsize]) ++commandlen;
- commandbuf[commandlen] = '\0';
- };
- XFree(cb);
- #endif
-};
-
-cvector vhistory;
-int histpos = 0;
-
-void history(int n)
-{
- static bool rec = false;
- if(!rec && n>=0 && n
+
+struct cline { char *cref; int outtime; };
+vector conlines;
+
+const int ndraw = 5;
+const int WORDWRAP = 80;
+int conskip = 0;
+
+bool saycommandon = false;
+string commandbuf;
+
+void setconskip(int n)
+{
+ conskip += n;
+ if(conskip<0) conskip = 0;
+};
+
+COMMANDN(conskip, setconskip, ARG_1INT);
+
+void conline(const char *sf, bool highlight) // add a line to the console buffer
+{
+ cline cl;
+ cl.cref = conlines.length()>100 ? conlines.pop().cref : newstringbuf(""); // constrain the buffer size
+ cl.outtime = lastmillis; // for how long to keep line on screen
+ conlines.insert(0,cl);
+ if(highlight) // show line in a different colour, for chat etc.
+ {
+ cl.cref[0] = '\f';
+ cl.cref[1] = 0;
+ strcat_s(cl.cref, sf);
+ }
+ else
+ {
+ strcpy_s(cl.cref, sf);
+ };
+ puts(cl.cref);
+ #ifndef _WIN32
+ fflush(stdout);
+ #endif
+};
+
+void conoutf(const char *s, ...)
+{
+ sprintf_sdv(sf, s);
+ s = sf;
+ int n = 0;
+ while(strlen(s)>WORDWRAP) // cut strings to fit on screen
+ {
+ string t;
+ strn0cpy(t, s, WORDWRAP+1);
+ conline(t, n++!=0);
+ s += WORDWRAP;
+ };
+ conline(s, n!=0);
+};
+
+void renderconsole() // render buffer taking into account time & scrolling
+{
+ int nd = 0;
+ char *refs[ndraw];
+ loopv(conlines) if(conskip ? i>=conskip-1 || i>=conlines.length()-ndraw : lastmillis-conlines[i].outtime<20000)
+ {
+ refs[nd++] = conlines[i].cref;
+ if(nd==ndraw) break;
+ };
+ loopj(nd)
+ {
+ draw_text(refs[j], FONTH/3, (FONTH/4*5)*(nd-j-1)+FONTH/3, 2);
+ };
+};
+
+// keymap is defined externally in keymap.cfg
+
+struct keym { int code; char *name; char *action; } keyms[256];
+int numkm = 0;
+
+void keymap(char *code, char *key, char *action)
+{
+ keyms[numkm].code = atoi(code);
+ keyms[numkm].name = newstring(key);
+ keyms[numkm++].action = newstringbuf(action);
+};
+
+COMMAND(keymap, ARG_3STR);
+
+void bindkey(char *key, char *action)
+{
+ for(char *x = key; *x; x++) *x = toupper(*x);
+ loopi(numkm) if(strcmp(keyms[i].name, key)==0)
+ {
+ strcpy_s(keyms[i].action, action);
+ return;
+ };
+ conoutf("unknown key \"%s\"", key);
+};
+
+COMMANDN(bind, bindkey, ARG_2STR);
+
+void saycommand(char *init) // turns input to the command line on or off
+{
+ SDL_EnableUNICODE(saycommandon = (init!=NULL));
+ if(!editmode) keyrepeat(saycommandon);
+ if(!init) init = "";
+ strcpy_s(commandbuf, init);
+};
+
+void mapmsg(char *s) { strn0cpy(hdr.maptitle, s, 128); };
+
+COMMAND(saycommand, ARG_VARI);
+COMMAND(mapmsg, ARG_1STR);
+
+#ifndef _WIN32
+#include
+#include
+#endif
+
+void pasteconsole()
+{
+ #ifdef _WIN32
+ if(!IsClipboardFormatAvailable(CF_TEXT)) return;
+ if(!OpenClipboard(NULL)) return;
+ char *cb = (char *)GlobalLock(GetClipboardData(CF_TEXT));
+ strcat_s(commandbuf, cb);
+ GlobalUnlock(cb);
+ CloseClipboard();
+ #else
+ SDL_SysWMinfo wminfo;
+ SDL_VERSION(&wminfo.version);
+ wminfo.subsystem = SDL_SYSWM_X11;
+ if(!SDL_GetWMInfo(&wminfo)) return;
+ int cbsize;
+ char *cb = XFetchBytes(wminfo.info.x11.display, &cbsize);
+ if(!cb || !cbsize) return;
+ int commandlen = strlen(commandbuf);
+ for(char *cbline = cb, *cbend; commandlen + 1 < _MAXDEFSTR && cbline < &cb[cbsize]; cbline = cbend + 1)
+ {
+ cbend = (char *)memchr(cbline, '\0', &cb[cbsize] - cbline);
+ if(!cbend) cbend = &cb[cbsize];
+ if(commandlen + cbend - cbline + 1 > _MAXDEFSTR) cbend = cbline + _MAXDEFSTR - commandlen - 1;
+ memcpy(&commandbuf[commandlen], cbline, cbend - cbline);
+ commandlen += cbend - cbline;
+ commandbuf[commandlen] = '\n';
+ if(commandlen + 1 < _MAXDEFSTR && cbend < &cb[cbsize]) ++commandlen;
+ commandbuf[commandlen] = '\0';
+ };
+ XFree(cb);
+ #endif
+};
+
+cvector vhistory;
+int histpos = 0;
+
+void history(int n)
+{
+ static bool rec = false;
+ if(!rec && n>=0 && nstate==CS_DEAD) return; // do not allow dead players to edit to avoid state confusion
- if(!editmode && !allowedittoggle()) return; // not in most multiplayer modes
- if(!(editmode = !editmode))
- {
- settagareas(); // reset triggers to allow quick playtesting
- entinmap(player1); // find spawn closest to current floating pos
- }
- else
- {
- resettagareas(); // clear trigger areas to allow them to be edited
- player1->health = 100;
- if(m_classicsp) monsterclear(); // all monsters back at their spawns for editing
- projreset();
- };
- keyrepeat(editmode);
- selset = false;
- editing = editmode;
-};
-
-COMMANDN(edittoggle, toggleedit, ARG_NONE);
-
-void correctsel() // ensures above invariant
-{
- selset = !OUTBORD(sel.x, sel.y);
- int bsize = ssize-MINBORD;
- if(sel.xs+sel.x>bsize) sel.xs = bsize-sel.x;
- if(sel.ys+sel.y>bsize) sel.ys = bsize-sel.y;
- if(sel.xs<=0 || sel.ys<=0) selset = false;
-};
-
-bool noteditmode()
-{
- correctsel();
- if(!editmode) conoutf("this function is only allowed in edit mode");
- return !editmode;
-};
-
-bool noselection()
-{
- if(!selset) conoutf("no selection");
- return !selset;
-};
-
-#define EDITSEL if(noteditmode() || noselection()) return;
-#define EDITSELMP if(noteditmode() || noselection() || multiplayer()) return;
-#define EDITMP if(noteditmode() || multiplayer()) return;
-
-void selectpos(int x, int y, int xs, int ys)
-{
- block s = { x, y, xs, ys };
- sel = s;
- selh = 0;
- correctsel();
-};
-
-void makesel()
-{
- block s = { min(lastx,cx), min(lasty,cy), abs(lastx-cx)+1, abs(lasty-cy)+1 };
- sel = s;
- selh = max(lasth,ch);
- correctsel();
- if(selset) rtex = *S(sel.x, sel.y);
-};
-
-VAR(flrceil,0,0,2);
-
-float sheight(sqr *s, sqr *t, float z) // finds out z height when cursor points at wall
-{
- return !flrceil //z-s->floorceil-z
- ? (s->type==FHF ? s->floor-t->vdelta/4.0f : (float)s->floor)
- : (s->type==CHF ? s->ceil+t->vdelta/4.0f : (float)s->ceil);
-};
-
-void cursorupdate() // called every frame from hud
-{
- flrceil = ((int)(player1->pitch>=0))*2;
-
- volatile float x = worldpos.x; // volatile needed to prevent msvc7 optimizer bug?
- volatile float y = worldpos.y;
- volatile float z = worldpos.z;
-
- cx = (int)x;
- cy = (int)y;
-
- if(OUTBORD(cx, cy)) return;
- sqr *s = S(cx,cy);
-
- if(fabs(sheight(s,s,z)-z)>1) // selected wall
- {
- x += x>player1->o.x ? 0.5f : -0.5f; // find right wall cube
- y += y>player1->o.y ? 0.5f : -0.5f;
-
- cx = (int)x;
- cy = (int)y;
-
- if(OUTBORD(cx, cy)) return;
- };
-
- if(dragging) makesel();
-
- const int GRIDSIZE = 5;
- const float GRIDW = 0.5f;
- const float GRID8 = 2.0f;
- const float GRIDS = 2.0f;
- const int GRIDM = 0x7;
-
- // render editing grid
-
- for(int ix = cx-GRIDSIZE; ix<=cx+GRIDSIZE; ix++) for(int iy = cy-GRIDSIZE; iy<=cy+GRIDSIZE; iy++)
- {
- if(OUTBORD(ix, iy)) continue;
- sqr *s = S(ix,iy);
- if(SOLID(s)) continue;
- float h1 = sheight(s, s, z);
- float h2 = sheight(s, SWS(s,1,0,ssize), z);
- float h3 = sheight(s, SWS(s,1,1,ssize), z);
- float h4 = sheight(s, SWS(s,0,1,ssize), z);
- if(s->tag) linestyle(GRIDW, 0xFF, 0x40, 0x40);
- else if(s->type==FHF || s->type==CHF) linestyle(GRIDW, 0x80, 0xFF, 0x80);
- else linestyle(GRIDW, 0x80, 0x80, 0x80);
- block b = { ix, iy, 1, 1 };
- box(b, h1, h2, h3, h4);
- linestyle(GRID8, 0x40, 0x40, 0xFF);
- if(!(ix&GRIDM)) line(ix, iy, h1, ix, iy+1, h4);
- if(!(ix+1&GRIDM)) line(ix+1, iy, h2, ix+1, iy+1, h3);
- if(!(iy&GRIDM)) line(ix, iy, h1, ix+1, iy, h2);
- if(!(iy+1&GRIDM)) line(ix, iy+1, h4, ix+1, iy+1, h3);
- };
-
- if(!SOLID(s))
- {
- float ih = sheight(s, s, z);
- linestyle(GRIDS, 0xFF, 0xFF, 0xFF);
- block b = { cx, cy, 1, 1 };
- box(b, ih, sheight(s, SWS(s,1,0,ssize), z), sheight(s, SWS(s,1,1,ssize), z), sheight(s, SWS(s,0,1,ssize), z));
- linestyle(GRIDS, 0xFF, 0x00, 0x00);
- dot(cx, cy, ih);
- ch = (int)ih;
- };
-
- if(selset)
- {
- linestyle(GRIDS, 0xFF, 0x40, 0x40);
- box(sel, (float)selh, (float)selh, (float)selh, (float)selh);
- };
-};
-
-vector undos; // unlimited undo
-VARP(undomegs, 0, 1, 10); // bounded by n megs
-
-void pruneundos(int maxremain) // bound memory
-{
- int t = 0;
- loopvrev(undos)
- {
- t += undos[i]->xs*undos[i]->ys*sizeof(sqr);
- if(t>maxremain) free(undos.remove(i));
- };
-};
-
-void makeundo()
-{
- undos.add(blockcopy(sel));
- pruneundos(undomegs<<20);
-};
-
-void editundo()
-{
- EDITMP;
- if(undos.empty()) { conoutf("nothing more to undo"); return; };
- block *p = undos.pop();
- blockpaste(*p);
- free(p);
-};
-
-block *copybuf = NULL;
-
-void copy()
-{
- EDITSELMP;
- if(copybuf) free(copybuf);
- copybuf = blockcopy(sel);
-};
-
-void paste()
-{
- EDITMP;
- if(!copybuf) { conoutf("nothing to paste"); return; };
- sel.xs = copybuf->xs;
- sel.ys = copybuf->ys;
- correctsel();
- if(!selset || sel.xs!=copybuf->xs || sel.ys!=copybuf->ys) { conoutf("incorrect selection"); return; };
- makeundo();
- copybuf->x = sel.x;
- copybuf->y = sel.y;
- blockpaste(*copybuf);
-};
-
-void tofronttex() // maintain most recently used of the texture lists when applying texture
-{
- loopi(3)
- {
- int c = curedittex[i];
- if(c>=0)
- {
- uchar *p = hdr.texlists[i];
- int t = p[c];
- for(int a = c-1; a>=0; a--) p[a+1] = p[a];
- p[0] = t;
- curedittex[i] = -1;
- };
- };
-};
-
-void editdrag(bool isdown)
-{
- if(dragging = isdown)
- {
- lastx = cx;
- lasty = cy;
- lasth = ch;
- selset = false;
- tofronttex();
- };
- makesel();
-};
-
-// the core editing function. all the *xy functions perform the core operations
-// and are also called directly from the network, the function below it is strictly
-// triggered locally. They all have very similar structure.
-
-void editheightxy(bool isfloor, int amount, block &sel)
-{
- loopselxy(if(isfloor)
- {
- s->floor += amount;
- if(s->floor>=s->ceil) s->floor = s->ceil-1;
- }
- else
- {
- s->ceil += amount;
- if(s->ceil<=s->floor) s->ceil = s->floor+1;
- });
-};
-
-void editheight(int flr, int amount)
-{
- EDITSEL;
- bool isfloor = flr==0;
- editheightxy(isfloor, amount, sel);
- addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount);
-};
-
-COMMAND(editheight, ARG_2INT);
-
-void edittexxy(int type, int t, block &sel)
-{
- loopselxy(switch(type)
- {
- case 0: s->ftex = t; break;
- case 1: s->wtex = t; break;
- case 2: s->ctex = t; break;
- case 3: s->utex = t; break;
- });
-};
-
-void edittex(int type, int dir)
-{
- EDITSEL;
- if(type<0 || type>3) return;
- if(type!=lasttype) { tofronttex(); lasttype = type; };
- int atype = type==3 ? 1 : type;
- int i = curedittex[atype];
- i = i<0 ? 0 : i+dir;
- curedittex[atype] = i = min(max(i, 0), 255);
- int t = lasttex = hdr.texlists[atype][i];
- edittexxy(type, t, sel);
- addmsg(1, 7, SV_EDITT, sel.x, sel.y, sel.xs, sel.ys, type, t);
-};
-
-void replace()
-{
- EDITSELMP;
- loop(x,ssize) loop(y,ssize)
- {
- sqr *s = S(x, y);
- switch(lasttype)
- {
- case 0: if(s->ftex == rtex.ftex) s->ftex = lasttex; break;
- case 1: if(s->wtex == rtex.wtex) s->wtex = lasttex; break;
- case 2: if(s->ctex == rtex.ctex) s->ctex = lasttex; break;
- case 3: if(s->utex == rtex.utex) s->utex = lasttex; break;
- };
- };
- block b = { 0, 0, ssize, ssize };
- remip(b);
-};
-
-void edittypexy(int type, block &sel)
-{
- loopselxy(s->type = type);
-};
-
-void edittype(int type)
-{
- EDITSEL;
- if(type==CORNER && (sel.xs!=sel.ys || sel.xs==3 || sel.xs>4 && sel.xs!=8
- || sel.x&~-sel.xs || sel.y&~-sel.ys))
- { conoutf("corner selection must be power of 2 aligned"); return; };
- edittypexy(type, sel);
- addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type);
-};
-
-void heightfield(int t) { edittype(t==0 ? FHF : CHF); };
-void solid(int t) { edittype(t==0 ? SPACE : SOLID); };
-void corner() { edittype(CORNER); };
-
-COMMAND(heightfield, ARG_1INT);
-COMMAND(solid, ARG_1INT);
-COMMAND(corner, ARG_NONE);
-
-void editequalisexy(bool isfloor, block &sel)
-{
- int low = 127, hi = -128;
- loopselxy(
- {
- if(s->floorfloor;
- if(s->ceil>hi) hi = s->ceil;
- });
- loopselxy(
- {
- if(isfloor) s->floor = low; else s->ceil = hi;
- if(s->floor>=s->ceil) s->floor = s->ceil-1;
- });
-};
-
-void equalize(int flr)
-{
- bool isfloor = flr==0;
- EDITSEL;
- editequalisexy(isfloor, sel);
- addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor);
-};
-
-COMMAND(equalize, ARG_1INT);
-
-void setvdeltaxy(int delta, block &sel)
-{
- loopselxy(s->vdelta = max(s->vdelta+delta, 0));
- remipmore(sel);
-};
-
-void setvdelta(int delta)
-{
- EDITSEL;
- setvdeltaxy(delta, sel);
- addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta);
-};
-
-const int MAXARCHVERT = 50;
-int archverts[MAXARCHVERT][MAXARCHVERT];
-bool archvinit = false;
-
-void archvertex(int span, int vert, int delta)
-{
- if(!archvinit)
- {
- archvinit = true;
- loop(s,MAXARCHVERT) loop(v,MAXARCHVERT) archverts[s][v] = 0;
- };
- if(span>=MAXARCHVERT || vert>=MAXARCHVERT || span<0 || vert<0) return;
- archverts[span][vert] = delta;
-};
-
-void arch(int sidedelta, int _a)
-{
- EDITSELMP;
- sel.xs++;
- sel.ys++;
- if(sel.xs>MAXARCHVERT) sel.xs = MAXARCHVERT;
- if(sel.ys>MAXARCHVERT) sel.ys = MAXARCHVERT;
- loopselxy(s->vdelta =
- sel.xs>sel.ys
- ? (archverts[sel.xs-1][x] + (y==0 || y==sel.ys-1 ? sidedelta : 0))
- : (archverts[sel.ys-1][y] + (x==0 || x==sel.xs-1 ? sidedelta : 0)));
- remipmore(sel);
-};
-
-void slope(int xd, int yd)
-{
- EDITSELMP;
- int off = 0;
- if(xd<0) off -= xd*sel.xs;
- if(yd<0) off -= yd*sel.ys;
- sel.xs++;
- sel.ys++;
- loopselxy(s->vdelta = xd*x+yd*y+off);
- remipmore(sel);
-};
-
-void perlin(int scale, int seed, int psize)
-{
- EDITSELMP;
- sel.xs++;
- sel.ys++;
- makeundo();
- sel.xs--;
- sel.ys--;
- perlinarea(sel, scale, seed, psize);
- sel.xs++;
- sel.ys++;
- remipmore(sel);
- sel.xs--;
- sel.ys--;
-};
-
-VARF(fullbright, 0, 0, 1,
- if(fullbright)
- {
- if(noteditmode()) return;
- loopi(mipsize) world[i].r = world[i].g = world[i].b = 176;
- };
-);
-
-void edittag(int tag)
-{
- EDITSELMP;
- loopselxy(s->tag = tag);
-};
-
-void newent(char *what, char *a1, char *a2, char *a3, char *a4)
-{
- EDITSEL;
- newentity(sel.x, sel.y, (int)player1->o.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
-};
-
-COMMANDN(select, selectpos, ARG_4INT);
-COMMAND(edittag, ARG_1INT);
-COMMAND(replace, ARG_NONE);
-COMMAND(archvertex, ARG_3INT);
-COMMAND(arch, ARG_2INT);
-COMMAND(slope, ARG_2INT);
-COMMANDN(vdelta, setvdelta, ARG_1INT);
-COMMANDN(undo, editundo, ARG_NONE);
-COMMAND(copy, ARG_NONE);
-COMMAND(paste, ARG_NONE);
-COMMAND(edittex, ARG_2INT);
-COMMAND(newent, ARG_5STR);
-COMMAND(perlin, ARG_3INT);
-
-
ADDED src/editing.cxx
Index: src/editing.cxx
==================================================================
--- /dev/null
+++ src/editing.cxx
@@ -0,0 +1,487 @@
+// editing.cpp: most map editing commands go here, entity editing commands are in world.cpp
+
+#include "cube.h"
+
+bool editmode = false;
+
+// the current selection, used by almost all editing commands
+// invariant: all code assumes that these are kept inside MINBORD distance of the edge of the map
+
+block sel =
+{
+ variable("selx", 0, 0, 4096, &sel.x, NULL, false),
+ variable("sely", 0, 0, 4096, &sel.y, NULL, false),
+ variable("selxs", 0, 0, 4096, &sel.xs, NULL, false),
+ variable("selys", 0, 0, 4096, &sel.ys, NULL, false),
+};
+
+int selh = 0;
+bool selset = false;
+
+#define loopselxy(b) { makeundo(); loop(x,sel.xs) loop(y,sel.ys) { sqr *s = S(sel.x+x, sel.y+y); b; }; remip(sel); }
+
+int cx, cy, ch;
+
+int curedittex[] = { -1, -1, -1 };
+
+bool dragging = false;
+int lastx, lasty, lasth;
+
+int lasttype = 0, lasttex = 0;
+sqr rtex;
+
+VAR(editing,0,0,1);
+
+void toggleedit()
+{
+ if(player1->state==CS_DEAD) return; // do not allow dead players to edit to avoid state confusion
+ if(!editmode && !allowedittoggle()) return; // not in most multiplayer modes
+ if(!(editmode = !editmode))
+ {
+ settagareas(); // reset triggers to allow quick playtesting
+ entinmap(player1); // find spawn closest to current floating pos
+ }
+ else
+ {
+ resettagareas(); // clear trigger areas to allow them to be edited
+ player1->health = 100;
+ if(m_classicsp) monsterclear(); // all monsters back at their spawns for editing
+ projreset();
+ };
+ keyrepeat(editmode);
+ selset = false;
+ editing = editmode;
+};
+
+COMMANDN(edittoggle, toggleedit, ARG_NONE);
+
+void correctsel() // ensures above invariant
+{
+ selset = !OUTBORD(sel.x, sel.y);
+ int bsize = ssize-MINBORD;
+ if(sel.xs+sel.x>bsize) sel.xs = bsize-sel.x;
+ if(sel.ys+sel.y>bsize) sel.ys = bsize-sel.y;
+ if(sel.xs<=0 || sel.ys<=0) selset = false;
+};
+
+bool noteditmode()
+{
+ correctsel();
+ if(!editmode) conoutf("this function is only allowed in edit mode");
+ return !editmode;
+};
+
+bool noselection()
+{
+ if(!selset) conoutf("no selection");
+ return !selset;
+};
+
+#define EDITSEL if(noteditmode() || noselection()) return;
+#define EDITSELMP if(noteditmode() || noselection() || multiplayer()) return;
+#define EDITMP if(noteditmode() || multiplayer()) return;
+
+void selectpos(int x, int y, int xs, int ys)
+{
+ block s = { x, y, xs, ys };
+ sel = s;
+ selh = 0;
+ correctsel();
+};
+
+void makesel()
+{
+ block s = { min(lastx,cx), min(lasty,cy), abs(lastx-cx)+1, abs(lasty-cy)+1 };
+ sel = s;
+ selh = max(lasth,ch);
+ correctsel();
+ if(selset) rtex = *S(sel.x, sel.y);
+};
+
+VAR(flrceil,0,0,2);
+
+float sheight(sqr *s, sqr *t, float z) // finds out z height when cursor points at wall
+{
+ return !flrceil //z-s->floorceil-z
+ ? (s->type==FHF ? s->floor-t->vdelta/4.0f : (float)s->floor)
+ : (s->type==CHF ? s->ceil+t->vdelta/4.0f : (float)s->ceil);
+};
+
+void cursorupdate() // called every frame from hud
+{
+ flrceil = ((int)(player1->pitch>=0))*2;
+
+ volatile float x = worldpos.x; // volatile needed to prevent msvc7 optimizer bug?
+ volatile float y = worldpos.y;
+ volatile float z = worldpos.z;
+
+ cx = (int)x;
+ cy = (int)y;
+
+ if(OUTBORD(cx, cy)) return;
+ sqr *s = S(cx,cy);
+
+ if(fabs(sheight(s,s,z)-z)>1) // selected wall
+ {
+ x += x>player1->o.x ? 0.5f : -0.5f; // find right wall cube
+ y += y>player1->o.y ? 0.5f : -0.5f;
+
+ cx = (int)x;
+ cy = (int)y;
+
+ if(OUTBORD(cx, cy)) return;
+ };
+
+ if(dragging) makesel();
+
+ const int GRIDSIZE = 5;
+ const float GRIDW = 0.5f;
+ const float GRID8 = 2.0f;
+ const float GRIDS = 2.0f;
+ const int GRIDM = 0x7;
+
+ // render editing grid
+
+ for(int ix = cx-GRIDSIZE; ix<=cx+GRIDSIZE; ix++) for(int iy = cy-GRIDSIZE; iy<=cy+GRIDSIZE; iy++)
+ {
+ if(OUTBORD(ix, iy)) continue;
+ sqr *s = S(ix,iy);
+ if(SOLID(s)) continue;
+ float h1 = sheight(s, s, z);
+ float h2 = sheight(s, SWS(s,1,0,ssize), z);
+ float h3 = sheight(s, SWS(s,1,1,ssize), z);
+ float h4 = sheight(s, SWS(s,0,1,ssize), z);
+ if(s->tag) linestyle(GRIDW, 0xFF, 0x40, 0x40);
+ else if(s->type==FHF || s->type==CHF) linestyle(GRIDW, 0x80, 0xFF, 0x80);
+ else linestyle(GRIDW, 0x80, 0x80, 0x80);
+ block b = { ix, iy, 1, 1 };
+ box(b, h1, h2, h3, h4);
+ linestyle(GRID8, 0x40, 0x40, 0xFF);
+ if(!(ix&GRIDM)) line(ix, iy, h1, ix, iy+1, h4);
+ if(!(ix+1&GRIDM)) line(ix+1, iy, h2, ix+1, iy+1, h3);
+ if(!(iy&GRIDM)) line(ix, iy, h1, ix+1, iy, h2);
+ if(!(iy+1&GRIDM)) line(ix, iy+1, h4, ix+1, iy+1, h3);
+ };
+
+ if(!SOLID(s))
+ {
+ float ih = sheight(s, s, z);
+ linestyle(GRIDS, 0xFF, 0xFF, 0xFF);
+ block b = { cx, cy, 1, 1 };
+ box(b, ih, sheight(s, SWS(s,1,0,ssize), z), sheight(s, SWS(s,1,1,ssize), z), sheight(s, SWS(s,0,1,ssize), z));
+ linestyle(GRIDS, 0xFF, 0x00, 0x00);
+ dot(cx, cy, ih);
+ ch = (int)ih;
+ };
+
+ if(selset)
+ {
+ linestyle(GRIDS, 0xFF, 0x40, 0x40);
+ box(sel, (float)selh, (float)selh, (float)selh, (float)selh);
+ };
+};
+
+vector undos; // unlimited undo
+VARP(undomegs, 0, 1, 10); // bounded by n megs
+
+void pruneundos(int maxremain) // bound memory
+{
+ int t = 0;
+ loopvrev(undos)
+ {
+ t += undos[i]->xs*undos[i]->ys*sizeof(sqr);
+ if(t>maxremain) free(undos.remove(i));
+ };
+};
+
+void makeundo()
+{
+ undos.add(blockcopy(sel));
+ pruneundos(undomegs<<20);
+};
+
+void editundo()
+{
+ EDITMP;
+ if(undos.empty()) { conoutf("nothing more to undo"); return; };
+ block *p = undos.pop();
+ blockpaste(*p);
+ free(p);
+};
+
+block *copybuf = NULL;
+
+void copy()
+{
+ EDITSELMP;
+ if(copybuf) free(copybuf);
+ copybuf = blockcopy(sel);
+};
+
+void paste()
+{
+ EDITMP;
+ if(!copybuf) { conoutf("nothing to paste"); return; };
+ sel.xs = copybuf->xs;
+ sel.ys = copybuf->ys;
+ correctsel();
+ if(!selset || sel.xs!=copybuf->xs || sel.ys!=copybuf->ys) { conoutf("incorrect selection"); return; };
+ makeundo();
+ copybuf->x = sel.x;
+ copybuf->y = sel.y;
+ blockpaste(*copybuf);
+};
+
+void tofronttex() // maintain most recently used of the texture lists when applying texture
+{
+ loopi(3)
+ {
+ int c = curedittex[i];
+ if(c>=0)
+ {
+ uchar *p = hdr.texlists[i];
+ int t = p[c];
+ for(int a = c-1; a>=0; a--) p[a+1] = p[a];
+ p[0] = t;
+ curedittex[i] = -1;
+ };
+ };
+};
+
+void editdrag(bool isdown)
+{
+ if(dragging = isdown)
+ {
+ lastx = cx;
+ lasty = cy;
+ lasth = ch;
+ selset = false;
+ tofronttex();
+ };
+ makesel();
+};
+
+// the core editing function. all the *xy functions perform the core operations
+// and are also called directly from the network, the function below it is strictly
+// triggered locally. They all have very similar structure.
+
+void editheightxy(bool isfloor, int amount, block &sel)
+{
+ loopselxy(if(isfloor)
+ {
+ s->floor += amount;
+ if(s->floor>=s->ceil) s->floor = s->ceil-1;
+ }
+ else
+ {
+ s->ceil += amount;
+ if(s->ceil<=s->floor) s->ceil = s->floor+1;
+ });
+};
+
+void editheight(int flr, int amount)
+{
+ EDITSEL;
+ bool isfloor = flr==0;
+ editheightxy(isfloor, amount, sel);
+ addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount);
+};
+
+COMMAND(editheight, ARG_2INT);
+
+void edittexxy(int type, int t, block &sel)
+{
+ loopselxy(switch(type)
+ {
+ case 0: s->ftex = t; break;
+ case 1: s->wtex = t; break;
+ case 2: s->ctex = t; break;
+ case 3: s->utex = t; break;
+ });
+};
+
+void edittex(int type, int dir)
+{
+ EDITSEL;
+ if(type<0 || type>3) return;
+ if(type!=lasttype) { tofronttex(); lasttype = type; };
+ int atype = type==3 ? 1 : type;
+ int i = curedittex[atype];
+ i = i<0 ? 0 : i+dir;
+ curedittex[atype] = i = min(max(i, 0), 255);
+ int t = lasttex = hdr.texlists[atype][i];
+ edittexxy(type, t, sel);
+ addmsg(1, 7, SV_EDITT, sel.x, sel.y, sel.xs, sel.ys, type, t);
+};
+
+void replace()
+{
+ EDITSELMP;
+ loop(x,ssize) loop(y,ssize)
+ {
+ sqr *s = S(x, y);
+ switch(lasttype)
+ {
+ case 0: if(s->ftex == rtex.ftex) s->ftex = lasttex; break;
+ case 1: if(s->wtex == rtex.wtex) s->wtex = lasttex; break;
+ case 2: if(s->ctex == rtex.ctex) s->ctex = lasttex; break;
+ case 3: if(s->utex == rtex.utex) s->utex = lasttex; break;
+ };
+ };
+ block b = { 0, 0, ssize, ssize };
+ remip(b);
+};
+
+void edittypexy(int type, block &sel)
+{
+ loopselxy(s->type = type);
+};
+
+void edittype(int type)
+{
+ EDITSEL;
+ if(type==CORNER && (sel.xs!=sel.ys || sel.xs==3 || sel.xs>4 && sel.xs!=8
+ || sel.x&~-sel.xs || sel.y&~-sel.ys))
+ { conoutf("corner selection must be power of 2 aligned"); return; };
+ edittypexy(type, sel);
+ addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type);
+};
+
+void heightfield(int t) { edittype(t==0 ? FHF : CHF); };
+void solid(int t) { edittype(t==0 ? SPACE : SOLID); };
+void corner() { edittype(CORNER); };
+
+COMMAND(heightfield, ARG_1INT);
+COMMAND(solid, ARG_1INT);
+COMMAND(corner, ARG_NONE);
+
+void editequalisexy(bool isfloor, block &sel)
+{
+ int low = 127, hi = -128;
+ loopselxy(
+ {
+ if(s->floorfloor;
+ if(s->ceil>hi) hi = s->ceil;
+ });
+ loopselxy(
+ {
+ if(isfloor) s->floor = low; else s->ceil = hi;
+ if(s->floor>=s->ceil) s->floor = s->ceil-1;
+ });
+};
+
+void equalize(int flr)
+{
+ bool isfloor = flr==0;
+ EDITSEL;
+ editequalisexy(isfloor, sel);
+ addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor);
+};
+
+COMMAND(equalize, ARG_1INT);
+
+void setvdeltaxy(int delta, block &sel)
+{
+ loopselxy(s->vdelta = max(s->vdelta+delta, 0));
+ remipmore(sel);
+};
+
+void setvdelta(int delta)
+{
+ EDITSEL;
+ setvdeltaxy(delta, sel);
+ addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta);
+};
+
+const int MAXARCHVERT = 50;
+int archverts[MAXARCHVERT][MAXARCHVERT];
+bool archvinit = false;
+
+void archvertex(int span, int vert, int delta)
+{
+ if(!archvinit)
+ {
+ archvinit = true;
+ loop(s,MAXARCHVERT) loop(v,MAXARCHVERT) archverts[s][v] = 0;
+ };
+ if(span>=MAXARCHVERT || vert>=MAXARCHVERT || span<0 || vert<0) return;
+ archverts[span][vert] = delta;
+};
+
+void arch(int sidedelta, int _a)
+{
+ EDITSELMP;
+ sel.xs++;
+ sel.ys++;
+ if(sel.xs>MAXARCHVERT) sel.xs = MAXARCHVERT;
+ if(sel.ys>MAXARCHVERT) sel.ys = MAXARCHVERT;
+ loopselxy(s->vdelta =
+ sel.xs>sel.ys
+ ? (archverts[sel.xs-1][x] + (y==0 || y==sel.ys-1 ? sidedelta : 0))
+ : (archverts[sel.ys-1][y] + (x==0 || x==sel.xs-1 ? sidedelta : 0)));
+ remipmore(sel);
+};
+
+void slope(int xd, int yd)
+{
+ EDITSELMP;
+ int off = 0;
+ if(xd<0) off -= xd*sel.xs;
+ if(yd<0) off -= yd*sel.ys;
+ sel.xs++;
+ sel.ys++;
+ loopselxy(s->vdelta = xd*x+yd*y+off);
+ remipmore(sel);
+};
+
+void perlin(int scale, int seed, int psize)
+{
+ EDITSELMP;
+ sel.xs++;
+ sel.ys++;
+ makeundo();
+ sel.xs--;
+ sel.ys--;
+ perlinarea(sel, scale, seed, psize);
+ sel.xs++;
+ sel.ys++;
+ remipmore(sel);
+ sel.xs--;
+ sel.ys--;
+};
+
+VARF(fullbright, 0, 0, 1,
+ if(fullbright)
+ {
+ if(noteditmode()) return;
+ loopi(mipsize) world[i].r = world[i].g = world[i].b = 176;
+ };
+);
+
+void edittag(int tag)
+{
+ EDITSELMP;
+ loopselxy(s->tag = tag);
+};
+
+void newent(char *what, char *a1, char *a2, char *a3, char *a4)
+{
+ EDITSEL;
+ newentity(sel.x, sel.y, (int)player1->o.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
+};
+
+COMMANDN(select, selectpos, ARG_4INT);
+COMMAND(edittag, ARG_1INT);
+COMMAND(replace, ARG_NONE);
+COMMAND(archvertex, ARG_3INT);
+COMMAND(arch, ARG_2INT);
+COMMAND(slope, ARG_2INT);
+COMMANDN(vdelta, setvdelta, ARG_1INT);
+COMMANDN(undo, editundo, ARG_NONE);
+COMMAND(copy, ARG_NONE);
+COMMAND(paste, ARG_NONE);
+COMMAND(edittex, ARG_2INT);
+COMMAND(newent, ARG_5STR);
+COMMAND(perlin, ARG_3INT);
+
+
DELETED src/entities.cpp
Index: src/entities.cpp
==================================================================
--- src/entities.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-// entities.cpp: map entity related functions (pickup etc.)
-
-#include "cube.h"
-
-vector ents;
-
-char *entmdlnames[] =
-{
- "shells", "bullets", "rockets", "rrounds", "health", "boost",
- "g_armour", "y_armour", "quad", "teleporter",
-};
-
-int triggertime = 0;
-
-void renderent(entity &e, char *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f)
-{
- rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z+S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime);
-};
-
-void renderentities()
-{
- if(lastmillis>triggertime+1000) triggertime = 0;
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type==MAPMODEL)
- {
- mapmodelinfo &mmi = getmminfo(e.attr2);
- if(!&mmi) continue;
- rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad, e.x, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, e.y, (float)((e.attr1+7)-(e.attr1+7)%15), 0, false, 1.0f, 10.0f, mmi.snap);
- }
- else
- {
- if(OUTBORD(e.x, e.y)) continue;
- if(e.type!=CARROT)
- {
- if(!e.spawned && e.type!=TELEPORT) continue;
- if(e.typeTELEPORT) continue;
- renderent(e, entmdlnames[e.type-I_SHELLS], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f);
- }
- else switch(e.attr2)
- {
- case 1:
- case 3:
- continue;
-
- case 2:
- case 0:
- if(!e.spawned) continue;
- renderent(e, "carrot", (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/(e.attr2 ? 1.0f : 10.0f));
- break;
-
- case 4: renderent(e, "switch2", 3, (float)e.attr3*90, (!e.spawned && !triggertime) ? 1 : 0, (e.spawned || !triggertime) ? 1 : 2, triggertime, 1050.0f); break;
- case 5: renderent(e, "switch1", -0.15f, (float)e.attr3*90, (!e.spawned && !triggertime) ? 30 : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break;
- };
- };
- };
-};
-
-struct itemstat { int add, max, sound; } itemstats[] =
-{
- 10, 50, S_ITEMAMMO,
- 20, 100, S_ITEMAMMO,
- 5, 25, S_ITEMAMMO,
- 5, 25, S_ITEMAMMO,
- 25, 100, S_ITEMHEALTH,
- 50, 200, S_ITEMHEALTH,
- 100, 100, S_ITEMARMOUR,
- 150, 150, S_ITEMARMOUR,
- 20000, 30000, S_ITEMPUP,
-};
-
-void baseammo(int gun) { player1->ammo[gun] = itemstats[gun-1].add*2; };
-
-// these two functions are called when the server acknowledges that you really
-// picked up the item (in multiplayer someone may grab it before you).
-
-void radditem(int i, int &v)
-{
- itemstat &is = itemstats[ents[i].type-I_SHELLS];
- ents[i].spawned = false;
- v += is.add;
- if(v>is.max) v = is.max;
- playsoundc(is.sound);
-};
-
-void realpickup(int n, dynent *d)
-{
- switch(ents[n].type)
- {
- case I_SHELLS: radditem(n, d->ammo[1]); break;
- case I_BULLETS: radditem(n, d->ammo[2]); break;
- case I_ROCKETS: radditem(n, d->ammo[3]); break;
- case I_ROUNDS: radditem(n, d->ammo[4]); break;
- case I_HEALTH: radditem(n, d->health); break;
- case I_BOOST: radditem(n, d->health); break;
-
- case I_GREENARMOUR:
- radditem(n, d->armour);
- d->armourtype = A_GREEN;
- break;
-
- case I_YELLOWARMOUR:
- radditem(n, d->armour);
- d->armourtype = A_YELLOW;
- break;
-
- case I_QUAD:
- radditem(n, d->quadmillis);
- conoutf("you got the quad!");
- break;
- };
-};
-
-// these functions are called when the client touches the item
-
-void additem(int i, int &v, int spawnsec)
-{
- if(vo.x = ents[e].x;
- d->o.y = ents[e].y;
- d->o.z = ents[e].z;
- d->yaw = ents[e].attr1;
- d->pitch = 0;
- d->vel.x = d->vel.y = d->vel.z = 0;
- entinmap(d);
- playsoundc(S_TELEPORT);
- break;
- };
- };
-};
-
-void pickup(int n, dynent *d)
-{
- int np = 1;
- loopv(players) if(players[i]) np++;
- np = np<3 ? 4 : (np>4 ? 2 : 3); // spawn times are dependent on number of players
- int ammo = np*2;
- switch(ents[n].type)
- {
- case I_SHELLS: additem(n, d->ammo[1], ammo); break;
- case I_BULLETS: additem(n, d->ammo[2], ammo); break;
- case I_ROCKETS: additem(n, d->ammo[3], ammo); break;
- case I_ROUNDS: additem(n, d->ammo[4], ammo); break;
- case I_HEALTH: additem(n, d->health, np*5); break;
- case I_BOOST: additem(n, d->health, 60); break;
-
- case I_GREENARMOUR:
- // (100h/100g only absorbs 166 damage)
- if(d->armourtype==A_YELLOW && d->armour>66) break;
- additem(n, d->armour, 20);
- break;
-
- case I_YELLOWARMOUR:
- additem(n, d->armour, 20);
- break;
-
- case I_QUAD:
- additem(n, d->quadmillis, 60);
- break;
-
- case CARROT:
- ents[n].spawned = false;
- triggertime = lastmillis;
- trigger(ents[n].attr1, ents[n].attr2, false); // needs to go over server for multiplayer
- break;
-
- case TELEPORT:
- {
- static int lastteleport = 0;
- if(lastmillis-lastteleport<500) break;
- lastteleport = lastmillis;
- teleport(n, d);
- break;
- };
-
- case JUMPPAD:
- {
- static int lastjumppad = 0;
- if(lastmillis-lastjumppad<300) break;
- lastjumppad = lastmillis;
- vec v = { (int)(char)ents[n].attr3/10.0f, (int)(char)ents[n].attr2/10.0f, ents[n].attr1/10.0f };
- player1->vel.z = 0;
- vadd(player1->vel, v);
- playsoundc(S_JUMPPAD);
- break;
- };
- };
-};
-
-void checkitems()
-{
- if(editmode) return;
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type==NOTUSED) continue;
- if(!ents[i].spawned && e.type!=TELEPORT && e.type!=JUMPPAD) continue;
- if(OUTBORD(e.x, e.y)) continue;
- vec v = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
- vdist(dist, t, player1->o, v);
- if(dist<(e.type==TELEPORT ? 4 : 2.5)) pickup(i, player1);
- };
-};
-
-void checkquad(int time)
-{
- if(player1->quadmillis && (player1->quadmillis -= time)<0)
- {
- player1->quadmillis = 0;
- playsoundc(S_PUPOUT);
- conoutf("quad damage is over");
- };
-};
-
-void putitems(uchar *&p) // puts items in network stream and also spawns them locally
-{
- loopv(ents) if((ents[i].type>=I_SHELLS && ents[i].type<=I_QUAD) || ents[i].type==CARROT)
- {
- putint(p, i);
- ents[i].spawned = true;
- };
-};
-
-void resetspawns() { loopv(ents) ents[i].spawned = false; };
-void setspawn(uint i, bool on) { if(i<(uint)ents.length()) ents[i].spawned = on; };
ADDED src/entities.cxx
Index: src/entities.cxx
==================================================================
--- /dev/null
+++ src/entities.cxx
@@ -0,0 +1,242 @@
+// entities.cpp: map entity related functions (pickup etc.)
+
+#include "cube.h"
+
+vector ents;
+
+char *entmdlnames[] =
+{
+ "shells", "bullets", "rockets", "rrounds", "health", "boost",
+ "g_armour", "y_armour", "quad", "teleporter",
+};
+
+int triggertime = 0;
+
+void renderent(entity &e, char *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f)
+{
+ rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z+S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime);
+};
+
+void renderentities()
+{
+ if(lastmillis>triggertime+1000) triggertime = 0;
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type==MAPMODEL)
+ {
+ mapmodelinfo &mmi = getmminfo(e.attr2);
+ if(!&mmi) continue;
+ rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad, e.x, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, e.y, (float)((e.attr1+7)-(e.attr1+7)%15), 0, false, 1.0f, 10.0f, mmi.snap);
+ }
+ else
+ {
+ if(OUTBORD(e.x, e.y)) continue;
+ if(e.type!=CARROT)
+ {
+ if(!e.spawned && e.type!=TELEPORT) continue;
+ if(e.typeTELEPORT) continue;
+ renderent(e, entmdlnames[e.type-I_SHELLS], (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/10.0f);
+ }
+ else switch(e.attr2)
+ {
+ case 1:
+ case 3:
+ continue;
+
+ case 2:
+ case 0:
+ if(!e.spawned) continue;
+ renderent(e, "carrot", (float)(1+sin(lastmillis/100.0+e.x+e.y)/20), lastmillis/(e.attr2 ? 1.0f : 10.0f));
+ break;
+
+ case 4: renderent(e, "switch2", 3, (float)e.attr3*90, (!e.spawned && !triggertime) ? 1 : 0, (e.spawned || !triggertime) ? 1 : 2, triggertime, 1050.0f); break;
+ case 5: renderent(e, "switch1", -0.15f, (float)e.attr3*90, (!e.spawned && !triggertime) ? 30 : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break;
+ };
+ };
+ };
+};
+
+struct itemstat { int add, max, sound; } itemstats[] =
+{
+ 10, 50, S_ITEMAMMO,
+ 20, 100, S_ITEMAMMO,
+ 5, 25, S_ITEMAMMO,
+ 5, 25, S_ITEMAMMO,
+ 25, 100, S_ITEMHEALTH,
+ 50, 200, S_ITEMHEALTH,
+ 100, 100, S_ITEMARMOUR,
+ 150, 150, S_ITEMARMOUR,
+ 20000, 30000, S_ITEMPUP,
+};
+
+void baseammo(int gun) { player1->ammo[gun] = itemstats[gun-1].add*2; };
+
+// these two functions are called when the server acknowledges that you really
+// picked up the item (in multiplayer someone may grab it before you).
+
+void radditem(int i, int &v)
+{
+ itemstat &is = itemstats[ents[i].type-I_SHELLS];
+ ents[i].spawned = false;
+ v += is.add;
+ if(v>is.max) v = is.max;
+ playsoundc(is.sound);
+};
+
+void realpickup(int n, dynent *d)
+{
+ switch(ents[n].type)
+ {
+ case I_SHELLS: radditem(n, d->ammo[1]); break;
+ case I_BULLETS: radditem(n, d->ammo[2]); break;
+ case I_ROCKETS: radditem(n, d->ammo[3]); break;
+ case I_ROUNDS: radditem(n, d->ammo[4]); break;
+ case I_HEALTH: radditem(n, d->health); break;
+ case I_BOOST: radditem(n, d->health); break;
+
+ case I_GREENARMOUR:
+ radditem(n, d->armour);
+ d->armourtype = A_GREEN;
+ break;
+
+ case I_YELLOWARMOUR:
+ radditem(n, d->armour);
+ d->armourtype = A_YELLOW;
+ break;
+
+ case I_QUAD:
+ radditem(n, d->quadmillis);
+ conoutf("you got the quad!");
+ break;
+ };
+};
+
+// these functions are called when the client touches the item
+
+void additem(int i, int &v, int spawnsec)
+{
+ if(vo.x = ents[e].x;
+ d->o.y = ents[e].y;
+ d->o.z = ents[e].z;
+ d->yaw = ents[e].attr1;
+ d->pitch = 0;
+ d->vel.x = d->vel.y = d->vel.z = 0;
+ entinmap(d);
+ playsoundc(S_TELEPORT);
+ break;
+ };
+ };
+};
+
+void pickup(int n, dynent *d)
+{
+ int np = 1;
+ loopv(players) if(players[i]) np++;
+ np = np<3 ? 4 : (np>4 ? 2 : 3); // spawn times are dependent on number of players
+ int ammo = np*2;
+ switch(ents[n].type)
+ {
+ case I_SHELLS: additem(n, d->ammo[1], ammo); break;
+ case I_BULLETS: additem(n, d->ammo[2], ammo); break;
+ case I_ROCKETS: additem(n, d->ammo[3], ammo); break;
+ case I_ROUNDS: additem(n, d->ammo[4], ammo); break;
+ case I_HEALTH: additem(n, d->health, np*5); break;
+ case I_BOOST: additem(n, d->health, 60); break;
+
+ case I_GREENARMOUR:
+ // (100h/100g only absorbs 166 damage)
+ if(d->armourtype==A_YELLOW && d->armour>66) break;
+ additem(n, d->armour, 20);
+ break;
+
+ case I_YELLOWARMOUR:
+ additem(n, d->armour, 20);
+ break;
+
+ case I_QUAD:
+ additem(n, d->quadmillis, 60);
+ break;
+
+ case CARROT:
+ ents[n].spawned = false;
+ triggertime = lastmillis;
+ trigger(ents[n].attr1, ents[n].attr2, false); // needs to go over server for multiplayer
+ break;
+
+ case TELEPORT:
+ {
+ static int lastteleport = 0;
+ if(lastmillis-lastteleport<500) break;
+ lastteleport = lastmillis;
+ teleport(n, d);
+ break;
+ };
+
+ case JUMPPAD:
+ {
+ static int lastjumppad = 0;
+ if(lastmillis-lastjumppad<300) break;
+ lastjumppad = lastmillis;
+ vec v = { (int)(char)ents[n].attr3/10.0f, (int)(char)ents[n].attr2/10.0f, ents[n].attr1/10.0f };
+ player1->vel.z = 0;
+ vadd(player1->vel, v);
+ playsoundc(S_JUMPPAD);
+ break;
+ };
+ };
+};
+
+void checkitems()
+{
+ if(editmode) return;
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type==NOTUSED) continue;
+ if(!ents[i].spawned && e.type!=TELEPORT && e.type!=JUMPPAD) continue;
+ if(OUTBORD(e.x, e.y)) continue;
+ vec v = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
+ vdist(dist, t, player1->o, v);
+ if(dist<(e.type==TELEPORT ? 4 : 2.5)) pickup(i, player1);
+ };
+};
+
+void checkquad(int time)
+{
+ if(player1->quadmillis && (player1->quadmillis -= time)<0)
+ {
+ player1->quadmillis = 0;
+ playsoundc(S_PUPOUT);
+ conoutf("quad damage is over");
+ };
+};
+
+void putitems(uchar *&p) // puts items in network stream and also spawns them locally
+{
+ loopv(ents) if((ents[i].type>=I_SHELLS && ents[i].type<=I_QUAD) || ents[i].type==CARROT)
+ {
+ putint(p, i);
+ ents[i].spawned = true;
+ };
+};
+
+void resetspawns() { loopv(ents) ents[i].spawned = false; };
+void setspawn(uint i, bool on) { if(i<(uint)ents.length()) ents[i].spawned = on; };
DELETED src/main.cpp
Index: src/main.cpp
==================================================================
--- src/main.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-// main.cpp: initialisation & main loop
-
-#include "cube.h"
-
-void cleanup(char *msg) // single program exit point;
-{
- stop();
- disconnect(true);
- writecfg();
- cleangl();
- cleansound();
- cleanupserver();
- SDL_ShowCursor(1);
- if(msg)
- {
- #ifdef WIN32
- MessageBox(NULL, msg, "cube fatal error", MB_OK|MB_SYSTEMMODAL);
- #else
- printf(msg);
- #endif
- };
- SDL_Quit();
- exit(1);
-};
-
-void quit() // normal exit
-{
- writeservercfg();
- cleanup(NULL);
-};
-
-void fatal(char *s, char *o) // failure exit
-{
- sprintf_sd(msg)("%s%s (%s)\n", s, o, SDL_GetError());
- cleanup(msg);
-};
-
-void *alloc(int s) // for some big chunks... most other allocs use the memory pool
-{
- void *b = calloc(1,s);
- if(!b) fatal("out of memory!");
- return b;
-};
-
-int scr_w = 640;
-int scr_h = 480;
-
-void screenshot()
-{
- SDL_Surface *image;
- SDL_Surface *temp;
- int idx;
- if(image = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))
- {
- if(temp = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))
- {
- glReadPixels(0, 0, scr_w, scr_h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);
- for (idx = 0; idxpixels+3*scr_w*idx;
- memcpy(dest, (char *)image->pixels+3*scr_w*(scr_h-1-idx), 3*scr_w);
- endianswap(dest, 3, scr_w);
- };
- sprintf_sd(buf)("screenshots/screenshot_%d.bmp", lastmillis);
- SDL_SaveBMP(temp, path(buf));
- SDL_FreeSurface(temp);
- };
- SDL_FreeSurface(image);
- };
-};
-
-COMMAND(screenshot, ARG_NONE);
-COMMAND(quit, ARG_NONE);
-
-void keyrepeat(bool on)
-{
- SDL_EnableKeyRepeat(on ? SDL_DEFAULT_REPEAT_DELAY : 0,
- SDL_DEFAULT_REPEAT_INTERVAL);
-};
-
-VARF(gamespeed, 10, 100, 1000, if(multiplayer()) gamespeed = 100);
-VARP(minmillis, 0, 5, 1000);
-
-int islittleendian = 1;
-int framesinmap = 0;
-
-int main(int argc, char **argv)
-{
- bool dedicated = false;
- int fs = SDL_FULLSCREEN, par = 0, uprate = 0, maxcl = 4;
- char *sdesc = "", *ip = "", *master = NULL, *passwd = "";
- islittleendian = *((char *)&islittleendian);
-
- #define log(s) conoutf("init: %s", s)
- log("sdl");
-
- for(int i = 1; i200) lastmillis = millis-200;
- else if(millis-lastmillis<1) lastmillis = millis-1;
- if(millis-lastmilliso.x, player1->o.y);
- readdepth(scr_w, scr_h);
- SDL_GL_SwapBuffers();
- extern void updatevol(); updatevol();
- if(framesinmap++<5) // cheap hack to get rid of initial sparklies, even when triple buffering etc.
- {
- player1->yaw += 5;
- gl_drawframe(scr_w, scr_h, fps);
- player1->yaw -= 5;
- };
- gl_drawframe(scr_w, scr_h, fps);
- SDL_Event event;
- int lasttype = 0, lastbut = 0;
- while(SDL_PollEvent(&event))
- {
- switch(event.type)
- {
- case SDL_QUIT:
- quit();
- break;
-
- case SDL_KEYDOWN:
- case SDL_KEYUP:
- keypress(event.key.keysym.sym, event.key.state==SDL_PRESSED, event.key.keysym.unicode);
- break;
-
- case SDL_MOUSEMOTION:
- if(ignore) { ignore--; break; };
- mousemove(event.motion.xrel, event.motion.yrel);
- break;
-
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- if(lasttype==event.type && lastbut==event.button.button) break; // why?? get event twice without it
- keypress(-event.button.button, event.button.state!=0, 0);
- lasttype = event.type;
- lastbut = event.button.button;
- break;
- };
- };
- };
- quit();
- return 1;
-};
-
-
ADDED src/main.cxx
Index: src/main.cxx
==================================================================
--- /dev/null
+++ src/main.cxx
@@ -0,0 +1,237 @@
+// main.cpp: initialisation & main loop
+
+#include "cube.h"
+
+void cleanup(char *msg) // single program exit point;
+{
+ stop();
+ disconnect(true);
+ writecfg();
+ cleangl();
+ cleansound();
+ cleanupserver();
+ SDL_ShowCursor(1);
+ if(msg)
+ {
+ #ifdef _WIN32
+ MessageBox(NULL, msg, "cube fatal error", MB_OK|MB_SYSTEMMODAL);
+ #else
+ printf(msg);
+ #endif
+ };
+ SDL_Quit();
+ exit(1);
+};
+
+void quit() // normal exit
+{
+ writeservercfg();
+ cleanup(NULL);
+};
+
+void fatal(char *s, char *o) // failure exit
+{
+ sprintf_sd(msg)("%s%s (%s)\n", s, o, SDL_GetError());
+ cleanup(msg);
+};
+
+void *alloc(int s) // for some big chunks... most other allocs use the memory pool
+{
+ void *b = calloc(1,s);
+ if(!b) fatal("out of memory!");
+ return b;
+};
+
+int scr_w = 640;
+int scr_h = 480;
+
+void screenshot()
+{
+ SDL_Surface *image;
+ SDL_Surface *temp;
+ int idx;
+ if(image = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))
+ {
+ if(temp = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))
+ {
+ glReadPixels(0, 0, scr_w, scr_h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);
+ for (idx = 0; idxpixels+3*scr_w*idx;
+ memcpy(dest, (char *)image->pixels+3*scr_w*(scr_h-1-idx), 3*scr_w);
+ endianswap(dest, 3, scr_w);
+ };
+ sprintf_sd(buf)("screenshots/screenshot_%d.bmp", lastmillis);
+ SDL_SaveBMP(temp, path(buf));
+ SDL_FreeSurface(temp);
+ };
+ SDL_FreeSurface(image);
+ };
+};
+
+COMMAND(screenshot, ARG_NONE);
+COMMAND(quit, ARG_NONE);
+
+void keyrepeat(bool on)
+{
+ SDL_EnableKeyRepeat(on ? SDL_DEFAULT_REPEAT_DELAY : 0,
+ SDL_DEFAULT_REPEAT_INTERVAL);
+};
+
+VARF(gamespeed, 10, 100, 1000, if(multiplayer()) gamespeed = 100);
+VARP(minmillis, 0, 5, 1000);
+
+int islittleendian = 1;
+int framesinmap = 0;
+
+int main(int argc, char **argv)
+{
+ bool dedicated = false;
+ int fs = SDL_FULLSCREEN, par = 0, uprate = 0, maxcl = 4;
+ char *sdesc = "", *ip = "", *master = NULL, *passwd = "";
+ islittleendian = *((char *)&islittleendian);
+
+ #define log(s) conoutf("init: %s", s)
+ log("sdl");
+
+ for(int i = 1; i200) lastmillis = millis-200;
+ else if(millis-lastmillis<1) lastmillis = millis-1;
+ if(millis-lastmilliso.x, player1->o.y);
+ readdepth(scr_w, scr_h);
+ SDL_GL_SwapBuffers();
+ extern void updatevol(); updatevol();
+ if(framesinmap++<5) // cheap hack to get rid of initial sparklies, even when triple buffering etc.
+ {
+ player1->yaw += 5;
+ gl_drawframe(scr_w, scr_h, fps);
+ player1->yaw -= 5;
+ };
+ gl_drawframe(scr_w, scr_h, fps);
+ SDL_Event event;
+ int lasttype = 0, lastbut = 0;
+ while(SDL_PollEvent(&event))
+ {
+ switch(event.type)
+ {
+ case SDL_QUIT:
+ quit();
+ break;
+
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ keypress(event.key.keysym.sym, event.key.state==SDL_PRESSED, event.key.keysym.unicode);
+ break;
+
+ case SDL_MOUSEMOTION:
+ if(ignore) { ignore--; break; };
+ mousemove(event.motion.xrel, event.motion.yrel);
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ if(lasttype==event.type && lastbut==event.button.button) break; // why?? get event twice without it
+ keypress(-event.button.button, event.button.state!=0, 0);
+ lasttype = event.type;
+ lastbut = event.button.button;
+ break;
+ };
+ };
+ };
+ quit();
+ return 1;
+};
+
+
DELETED src/menus.cpp
Index: src/menus.cpp
==================================================================
--- src/menus.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-// menus.cpp: ingame menu system (also used for scores and serverlist)
-
-#include "cube.h"
-
-struct mitem { char *text, *action; };
-
-struct gmenu
-{
- char *name;
- vector items;
- int mwidth;
- int menusel;
-};
-
-vector menus;
-
-int vmenu = -1;
-
-ivector menustack;
-
-void menuset(int menu)
-{
- if((vmenu = menu)>=1) resetmovement(player1);
- if(vmenu==1) menus[1].menusel = 0;
-};
-
-void showmenu(char *name)
-{
- loopv(menus) if(i>1 && strcmp(menus[i].name, name)==0)
- {
- menuset(i);
- return;
- };
-};
-
-int menucompare(mitem *a, mitem *b)
-{
- int x = atoi(a->text);
- int y = atoi(b->text);
- if(x>y) return -1;
- if(x1 ? "[ %s menu ]" : "%s", m.name);
- int mdisp = m.items.length();
- int w = 0;
- loopi(mdisp)
- {
- int x = text_width(m.items[i].text);
- if(x>w) w = x;
- };
- int tw = text_width(title);
- if(tw>w) w = tw;
- int step = FONTH/4*5;
- int h = (mdisp+2)*step;
- int y = (VIRTH-h)/2;
- int x = (VIRTW-w)/2;
- blendbox(x-FONTH/2*3, y-FONTH, x+w+FONTH/2*3, y+h+FONTH, true);
- draw_text(title, x, y,2);
- y += FONTH*2;
- if(vmenu)
- {
- int bh = y+m.menusel*step;
- blendbox(x-FONTH, bh-10, x+w+FONTH, bh+FONTH+10, false);
- };
- loopj(mdisp)
- {
- draw_text(m.items[j].text, x, y, 2);
- y += step;
- };
- return true;
-};
-
-void newmenu(char *name)
-{
- gmenu &menu = menus.add();
- menu.name = newstring(name);
- menu.menusel = 0;
-};
-
-void menumanual(int m, int n, char *text)
-{
- if(!n) menus[m].items.setsize(0);
- mitem &mitem = menus[m].items.add();
- mitem.text = text;
- mitem.action = "";
-}
-
-void menuitem(char *text, char *action)
-{
- gmenu &menu = menus.last();
- mitem &mi = menu.items.add();
- mi.text = newstring(text);
- mi.action = action[0] ? newstring(action) : mi.text;
-};
-
-COMMAND(menuitem, ARG_2STR);
-COMMAND(showmenu, ARG_1STR);
-COMMAND(newmenu, ARG_1STR);
-
-bool menukey(int code, bool isdown)
-{
- if(vmenu<=0) return false;
- int menusel = menus[vmenu].menusel;
- if(isdown)
- {
- if(code==SDLK_ESCAPE)
- {
- menuset(-1);
- if(!menustack.empty()) menuset(menustack.pop());
- return true;
- }
- else if(code==SDLK_UP || code==-4) menusel--;
- else if(code==SDLK_DOWN || code==-5) menusel++;
- int n = menus[vmenu].items.length();
- if(menusel<0) menusel = n-1;
- else if(menusel>=n) menusel = 0;
- menus[vmenu].menusel = menusel;
- }
- else
- {
- if(code==SDLK_RETURN || code==-2)
- {
- char *action = menus[vmenu].items[menusel].action;
- if(vmenu==1) connects(getservername(menusel));
- menustack.add(vmenu);
- menuset(-1);
- execute(action, true);
- };
- };
- return true;
-};
ADDED src/menus.cxx
Index: src/menus.cxx
==================================================================
--- /dev/null
+++ src/menus.cxx
@@ -0,0 +1,145 @@
+// menus.cpp: ingame menu system (also used for scores and serverlist)
+
+#include "cube.h"
+
+struct mitem { char *text, *action; };
+
+struct gmenu
+{
+ char *name;
+ vector items;
+ int mwidth;
+ int menusel;
+};
+
+vector menus;
+
+int vmenu = -1;
+
+ivector menustack;
+
+void menuset(int menu)
+{
+ if((vmenu = menu)>=1) resetmovement(player1);
+ if(vmenu==1) menus[1].menusel = 0;
+};
+
+void showmenu(char *name)
+{
+ loopv(menus) if(i>1 && strcmp(menus[i].name, name)==0)
+ {
+ menuset(i);
+ return;
+ };
+};
+
+int menucompare(mitem *a, mitem *b)
+{
+ int x = atoi(a->text);
+ int y = atoi(b->text);
+ if(x>y) return -1;
+ if(x1 ? "[ %s menu ]" : "%s", m.name);
+ int mdisp = m.items.length();
+ int w = 0;
+ loopi(mdisp)
+ {
+ int x = text_width(m.items[i].text);
+ if(x>w) w = x;
+ };
+ int tw = text_width(title);
+ if(tw>w) w = tw;
+ int step = FONTH/4*5;
+ int h = (mdisp+2)*step;
+ int y = (VIRTH-h)/2;
+ int x = (VIRTW-w)/2;
+ blendbox(x-FONTH/2*3, y-FONTH, x+w+FONTH/2*3, y+h+FONTH, true);
+ draw_text(title, x, y,2);
+ y += FONTH*2;
+ if(vmenu)
+ {
+ int bh = y+m.menusel*step;
+ blendbox(x-FONTH, bh-10, x+w+FONTH, bh+FONTH+10, false);
+ };
+ loopj(mdisp)
+ {
+ draw_text(m.items[j].text, x, y, 2);
+ y += step;
+ };
+ return true;
+};
+
+void newmenu(char *name)
+{
+ gmenu &menu = menus.add();
+ menu.name = newstring(name);
+ menu.menusel = 0;
+};
+
+void menumanual(int m, int n, char *text)
+{
+ if(!n) menus[m].items.setsize(0);
+ mitem &mitem = menus[m].items.add();
+ mitem.text = text;
+ mitem.action = "";
+}
+
+void menuitem(char *text, char *action)
+{
+ gmenu &menu = menus.last();
+ mitem &mi = menu.items.add();
+ mi.text = newstring(text);
+ mi.action = action[0] ? newstring(action) : mi.text;
+};
+
+COMMAND(menuitem, ARG_2STR);
+COMMAND(showmenu, ARG_1STR);
+COMMAND(newmenu, ARG_1STR);
+
+bool menukey(int code, bool isdown)
+{
+ if(vmenu<=0) return false;
+ int menusel = menus[vmenu].menusel;
+ if(isdown)
+ {
+ if(code==SDLK_ESCAPE)
+ {
+ menuset(-1);
+ if(!menustack.empty()) menuset(menustack.pop());
+ return true;
+ }
+ else if(code==SDLK_UP || code==-4) menusel--;
+ else if(code==SDLK_DOWN || code==-5) menusel++;
+ int n = menus[vmenu].items.length();
+ if(menusel<0) menusel = n-1;
+ else if(menusel>=n) menusel = 0;
+ menus[vmenu].menusel = menusel;
+ }
+ else
+ {
+ if(code==SDLK_RETURN || code==-2)
+ {
+ char *action = menus[vmenu].items[menusel].action;
+ if(vmenu==1) connects(getservername(menusel));
+ menustack.add(vmenu);
+ menuset(-1);
+ execute(action, true);
+ };
+ };
+ return true;
+};
DELETED src/monster.cpp
Index: src/monster.cpp
==================================================================
--- src/monster.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-// monster.cpp: implements AI for single player monsters, currently client only
-
-#include "cube.h"
-
-dvector monsters;
-int nextmonster, spawnremain, numkilled, monstertotal, mtimestart;
-
-VARF(skill, 1, 3, 10, conoutf("skill is now %d", skill));
-
-dvector &getmonsters() { return monsters; };
-void restoremonsterstate() { loopv(monsters) if(monsters[i]->state==CS_DEAD) numkilled++; }; // for savegames
-
-#define TOTMFREQ 13
-#define NUMMONSTERTYPES 8
-
-struct monstertype // see docs for how these values modify behaviour
-{
- short gun, speed, health, freq, lag, rate, pain, loyalty, mscale, bscale;
- short painsound, diesound;
- char *name, *mdlname;
-}
-
-monstertypes[NUMMONSTERTYPES] =
-{
- { GUN_FIREBALL, 15, 100, 3, 0, 100, 800, 1, 10, 10, S_PAINO, S_DIE1, "an ogre", "monster/ogro" },
- { GUN_CG, 18, 70, 2, 70, 10, 400, 2, 8, 9, S_PAINR, S_DEATHR, "a rhino", "monster/rhino" },
- { GUN_SG, 14, 120, 1, 100, 300, 400, 4, 14, 14, S_PAINE, S_DEATHE, "ratamahatta", "monster/rat" },
- { GUN_RIFLE, 15, 200, 1, 80, 300, 300, 4, 18, 18, S_PAINS, S_DEATHS, "a slith", "monster/slith" },
- { GUN_RL, 13, 500, 1, 0, 100, 200, 6, 24, 24, S_PAINB, S_DEATHB, "bauul", "monster/bauul" },
- { GUN_BITE, 22, 50, 3, 0, 100, 400, 1, 12, 15, S_PAINP, S_PIGGR2, "a hellpig", "monster/hellpig" },
- { GUN_ICEBALL, 12, 250, 1, 0, 10, 400, 6, 18, 18, S_PAINH, S_DEATHH, "a knight", "monster/knight" },
- { GUN_SLIMEBALL, 15, 100, 1, 0, 200, 400, 2, 13, 10, S_PAIND, S_DEATHD, "a goblin", "monster/goblin" },
-};
-
-dynent *basicmonster(int type, int yaw, int state, int trigger, int move)
-{
- if(type>=NUMMONSTERTYPES)
- {
- conoutf("warning: unknown monster in spawn: %d", type);
- type = 0;
- };
- dynent *m = newdynent();
- monstertype *t = &monstertypes[m->mtype = type];
- m->eyeheight = 2.0f;
- m->aboveeye = 1.9f;
- m->radius *= t->bscale/10.0f;
- m->eyeheight *= t->bscale/10.0f;
- m->aboveeye *= t->bscale/10.0f;
- m->monsterstate = state;
- if(state!=M_SLEEP) spawnplayer(m);
- m->trigger = lastmillis+trigger;
- m->targetyaw = m->yaw = (float)yaw;
- m->move = move;
- m->enemy = player1;
- m->gunselect = t->gun;
- m->maxspeed = (float)t->speed;
- m->health = t->health;
- m->armour = 0;
- loopi(NUMGUNS) m->ammo[i] = 10000;
- m->pitch = 0;
- m->roll = 0;
- m->state = CS_ALIVE;
- m->anger = 0;
- strcpy_s(m->name, t->name);
- monsters.add(m);
- return m;
-};
-
-void spawnmonster() // spawn a random monster according to freq distribution in DMSP
-{
- int n = rnd(TOTMFREQ), type;
- for(int i = 0; ; i++) if((n -= monstertypes[i].freq)<0) { type = i; break; };
- basicmonster(type, rnd(360), M_SEARCH, 1000, 1);
-};
-
-void monsterclear() // called after map start of when toggling edit mode to reset/spawn all monsters to initial state
-{
- loopv(monsters) gp()->dealloc(monsters[i], sizeof(dynent));
- monsters.setsize(0);
- numkilled = 0;
- monstertotal = 0;
- spawnremain = 0;
- if(m_dmsp)
- {
- nextmonster = mtimestart = lastmillis+10000;
- monstertotal = spawnremain = gamemode<0 ? skill*10 : 0;
- }
- else if(m_classicsp)
- {
- mtimestart = lastmillis;
- loopv(ents) if(ents[i].type==MONSTER)
- {
- dynent *m = basicmonster(ents[i].attr2, ents[i].attr1, M_SLEEP, 100, 0);
- m->o.x = ents[i].x;
- m->o.y = ents[i].y;
- m->o.z = ents[i].z;
- entinmap(m);
- monstertotal++;
- };
- };
-};
-
-bool los(float lx, float ly, float lz, float bx, float by, float bz, vec &v) // height-correct line of sight for monster shooting/seeing
-{
- if(OUTBORD((int)lx, (int)ly) || OUTBORD((int)bx, (int)by)) return false;
- float dx = bx-lx;
- float dy = by-ly;
- int steps = (int)(sqrt(dx*dx+dy*dy)/0.9);
- if(!steps) return false;
- float x = lx;
- float y = ly;
- int i = 0;
- for(;;)
- {
- sqr *s = S(fast_f2nat(x), fast_f2nat(y));
- if(SOLID(s)) break;
- float floor = s->floor;
- if(s->type==FHF) floor -= s->vdelta/4.0f;
- float ceil = s->ceil;
- if(s->type==CHF) ceil += s->vdelta/4.0f;
- float rz = lz-((lz-bz)*(i/(float)steps));
- if(rzceil) break;
- v.x = x;
- v.y = y;
- v.z = rz;
- x += dx/(float)steps;
- y += dy/(float)steps;
- i++;
- };
- return i>=steps;
-};
-
-bool enemylos(dynent *m, vec &v)
-{
- v = m->o;
- return los(m->o.x, m->o.y, m->o.z, m->enemy->o.x, m->enemy->o.y, m->enemy->o.z, v);
-};
-
-// monster AI is sequenced using transitions: they are in a particular state where
-// they execute a particular behaviour until the trigger time is hit, and then they
-// reevaluate their situation based on the current state, the environment etc., and
-// transition to the next state. Transition timeframes are parametrized by difficulty
-// level (skill), faster transitions means quicker decision making means tougher AI.
-
-void transition(dynent *m, int state, int moving, int n, int r) // n = at skill 0, n/2 = at skill 10, r = added random factor
-{
- m->monsterstate = state;
- m->move = moving;
- n = n*130/100;
- m->trigger = lastmillis+n-skill*(n/16)+rnd(r+1);
-};
-
-void normalise(dynent *m, float angle)
-{
- while(m->yawyaw += 360.0f;
- while(m->yaw>angle+180.0f) m->yaw -= 360.0f;
-};
-
-void monsteraction(dynent *m) // main AI thinking routine, called every frame for every monster
-{
- if(m->enemy->state==CS_DEAD) { m->enemy = player1; m->anger = 0; };
- normalise(m, m->targetyaw);
- if(m->targetyaw>m->yaw) // slowly turn monster towards his target
- {
- m->yaw += curtime*0.5f;
- if(m->targetyawyaw) m->yaw = m->targetyaw;
- }
- else
- {
- m->yaw -= curtime*0.5f;
- if(m->targetyaw>m->yaw) m->yaw = m->targetyaw;
- };
-
- vdist(disttoenemy, vectoenemy, m->o, m->enemy->o);
- m->pitch = atan2(m->enemy->o.z-m->o.z, disttoenemy)*180/PI;
-
- if(m->blocked) // special case: if we run into scenery
- {
- m->blocked = false;
- if(!rnd(20000/monstertypes[m->mtype].speed)) // try to jump over obstackle (rare)
- {
- m->jumpnext = true;
- }
- else if(m->triggermonsterstate!=M_HOME || !rnd(5))) // search for a way around (common)
- {
- m->targetyaw += 180+rnd(180); // patented "random walk" AI pathfinding (tm) ;)
- transition(m, M_SEARCH, 1, 400, 1000);
- };
- };
-
- float enemyyaw = -(float)atan2(m->enemy->o.x - m->o.x, m->enemy->o.y - m->o.y)/PI*180+180;
-
- switch(m->monsterstate)
- {
- case M_PAIN:
- case M_ATTACKING:
- case M_SEARCH:
- if(m->triggeryaw);
- if(disttoenemy<8 // the better the angle to the player, the further the monster can see/hear
- ||(disttoenemy<16 && angle<135)
- ||(disttoenemy<32 && angle<90)
- ||(disttoenemy<64 && angle<45)
- || angle<10)
- {
- transition(m, M_HOME, 1, 500, 200);
- playsound(S_GRUNT1+rnd(2), &m->o);
- };
- break;
- };
-
- case M_AIMING: // this state is the delay between wanting to shoot and actually firing
- if(m->triggerlastaction = 0;
- m->attacking = true;
- shoot(m, m->attacktarget);
- transition(m, M_ATTACKING, 0, 600, 0);
- };
- break;
-
- case M_HOME: // monster has visual contact, heads straight for player and may want to shoot at any time
- m->targetyaw = enemyyaw;
- if(m->triggerenemy->state==CS_ALIVE) // get ready to fire
- {
- m->attacktarget = target;
- transition(m, M_AIMING, 0, monstertypes[m->mtype].lag, 10);
- }
- else // track player some more
- {
- transition(m, M_HOME, 1, monstertypes[m->mtype].rate, 0);
- };
- };
- };
- break;
- };
-
- moveplayer(m, 1, false); // use physics to move monster
-};
-
-void monsterpain(dynent *m, int damage, dynent *d)
-{
- if(d->monsterstate) // a monster hit us
- {
- if(m!=d) // guard for RL guys shooting themselves :)
- {
- m->anger++; // don't attack straight away, first get angry
- int anger = m->mtype==d->mtype ? m->anger/2 : m->anger;
- if(anger>=monstertypes[m->mtype].loyalty) m->enemy = d; // monster infight if very angry
- };
- }
- else // player hit us
- {
- m->anger = 0;
- m->enemy = d;
- };
- transition(m, M_PAIN, 0, monstertypes[m->mtype].pain,200); // in this state monster won't attack
- if((m->health -= damage)<=0)
- {
- m->state = CS_DEAD;
- m->lastaction = lastmillis;
- numkilled++;
- player1->frags = numkilled;
- playsound(monstertypes[m->mtype].diesound, &m->o);
- int remain = monstertotal-numkilled;
- if(remain>0 && remain<=5) conoutf("only %d monster(s) remaining", remain);
- }
- else
- {
- playsound(monstertypes[m->mtype].painsound, &m->o);
- };
-};
-
-void endsp(bool allkilled)
-{
- conoutf(allkilled ? "you have cleared the map!" : "you reached the exit!");
- conoutf("score: %d kills in %d seconds", numkilled, (lastmillis-mtimestart)/1000);
- monstertotal = 0;
- startintermission();
-};
-
-void monsterthink()
-{
- if(m_dmsp && spawnremain && lastmillis>nextmonster)
- {
- if(spawnremain--==monstertotal) conoutf("The invasion has begun!");
- nextmonster = lastmillis+1000;
- spawnmonster();
- };
-
- if(monstertotal && !spawnremain && numkilled==monstertotal) endsp(true);
-
- loopv(ents) // equivalent of player entity touch, but only teleports are used
- {
- entity &e = ents[i];
- if(e.type!=TELEPORT) continue;
- if(OUTBORD(e.x, e.y)) continue;
- vec v = { e.x, e.y, S(e.x, e.y)->floor };
- loopv(monsters) if(monsters[i]->state==CS_DEAD)
- {
- if(lastmillis-monsters[i]->lastaction<2000)
- {
- monsters[i]->move = 0;
- moveplayer(monsters[i], 1, false);
- };
- }
- else
- {
- v.z += monsters[i]->eyeheight;
- vdist(dist, t, monsters[i]->o, v);
- v.z -= monsters[i]->eyeheight;
- if(dist<4) teleport((int)(&e-&ents[0]), monsters[i]);
- };
- };
-
- loopv(monsters) if(monsters[i]->state==CS_ALIVE) monsteraction(monsters[i]);
-};
-
-void monsterrender()
-{
- loopv(monsters) renderclient(monsters[i], false, monstertypes[monsters[i]->mtype].mdlname, monsters[i]->mtype==5, monstertypes[monsters[i]->mtype].mscale/10.0f);
-};
ADDED src/monster.cxx
Index: src/monster.cxx
==================================================================
--- /dev/null
+++ src/monster.cxx
@@ -0,0 +1,338 @@
+// monster.cpp: implements AI for single player monsters, currently client only
+
+#include "cube.h"
+
+dvector monsters;
+int nextmonster, spawnremain, numkilled, monstertotal, mtimestart;
+
+VARF(skill, 1, 3, 10, conoutf("skill is now %d", skill));
+
+dvector &getmonsters() { return monsters; };
+void restoremonsterstate() { loopv(monsters) if(monsters[i]->state==CS_DEAD) numkilled++; }; // for savegames
+
+#define TOTMFREQ 13
+#define NUMMONSTERTYPES 8
+
+struct monstertype // see docs for how these values modify behaviour
+{
+ short gun, speed, health, freq, lag, rate, pain, loyalty, mscale, bscale;
+ short painsound, diesound;
+ char *name, *mdlname;
+}
+
+monstertypes[NUMMONSTERTYPES] =
+{
+ { GUN_FIREBALL, 15, 100, 3, 0, 100, 800, 1, 10, 10, S_PAINO, S_DIE1, "an ogre", "monster/ogro" },
+ { GUN_CG, 18, 70, 2, 70, 10, 400, 2, 8, 9, S_PAINR, S_DEATHR, "a rhino", "monster/rhino" },
+ { GUN_SG, 14, 120, 1, 100, 300, 400, 4, 14, 14, S_PAINE, S_DEATHE, "ratamahatta", "monster/rat" },
+ { GUN_RIFLE, 15, 200, 1, 80, 300, 300, 4, 18, 18, S_PAINS, S_DEATHS, "a slith", "monster/slith" },
+ { GUN_RL, 13, 500, 1, 0, 100, 200, 6, 24, 24, S_PAINB, S_DEATHB, "bauul", "monster/bauul" },
+ { GUN_BITE, 22, 50, 3, 0, 100, 400, 1, 12, 15, S_PAINP, S_PIGGR2, "a hellpig", "monster/hellpig" },
+ { GUN_ICEBALL, 12, 250, 1, 0, 10, 400, 6, 18, 18, S_PAINH, S_DEATHH, "a knight", "monster/knight" },
+ { GUN_SLIMEBALL, 15, 100, 1, 0, 200, 400, 2, 13, 10, S_PAIND, S_DEATHD, "a goblin", "monster/goblin" },
+};
+
+dynent *basicmonster(int type, int yaw, int state, int trigger, int move)
+{
+ if(type>=NUMMONSTERTYPES)
+ {
+ conoutf("warning: unknown monster in spawn: %d", type);
+ type = 0;
+ };
+ dynent *m = newdynent();
+ monstertype *t = &monstertypes[m->mtype = type];
+ m->eyeheight = 2.0f;
+ m->aboveeye = 1.9f;
+ m->radius *= t->bscale/10.0f;
+ m->eyeheight *= t->bscale/10.0f;
+ m->aboveeye *= t->bscale/10.0f;
+ m->monsterstate = state;
+ if(state!=M_SLEEP) spawnplayer(m);
+ m->trigger = lastmillis+trigger;
+ m->targetyaw = m->yaw = (float)yaw;
+ m->move = move;
+ m->enemy = player1;
+ m->gunselect = t->gun;
+ m->maxspeed = (float)t->speed;
+ m->health = t->health;
+ m->armour = 0;
+ loopi(NUMGUNS) m->ammo[i] = 10000;
+ m->pitch = 0;
+ m->roll = 0;
+ m->state = CS_ALIVE;
+ m->anger = 0;
+ strcpy_s(m->name, t->name);
+ monsters.add(m);
+ return m;
+};
+
+void spawnmonster() // spawn a random monster according to freq distribution in DMSP
+{
+ int n = rnd(TOTMFREQ), type;
+ for(int i = 0; ; i++) if((n -= monstertypes[i].freq)<0) { type = i; break; };
+ basicmonster(type, rnd(360), M_SEARCH, 1000, 1);
+};
+
+void monsterclear() // called after map start of when toggling edit mode to reset/spawn all monsters to initial state
+{
+ loopv(monsters) gp()->dealloc(monsters[i], sizeof(dynent));
+ monsters.setsize(0);
+ numkilled = 0;
+ monstertotal = 0;
+ spawnremain = 0;
+ if(m_dmsp)
+ {
+ nextmonster = mtimestart = lastmillis+10000;
+ monstertotal = spawnremain = gamemode<0 ? skill*10 : 0;
+ }
+ else if(m_classicsp)
+ {
+ mtimestart = lastmillis;
+ loopv(ents) if(ents[i].type==MONSTER)
+ {
+ dynent *m = basicmonster(ents[i].attr2, ents[i].attr1, M_SLEEP, 100, 0);
+ m->o.x = ents[i].x;
+ m->o.y = ents[i].y;
+ m->o.z = ents[i].z;
+ entinmap(m);
+ monstertotal++;
+ };
+ };
+};
+
+bool los(float lx, float ly, float lz, float bx, float by, float bz, vec &v) // height-correct line of sight for monster shooting/seeing
+{
+ if(OUTBORD((int)lx, (int)ly) || OUTBORD((int)bx, (int)by)) return false;
+ float dx = bx-lx;
+ float dy = by-ly;
+ int steps = (int)(sqrt(dx*dx+dy*dy)/0.9);
+ if(!steps) return false;
+ float x = lx;
+ float y = ly;
+ int i = 0;
+ for(;;)
+ {
+ sqr *s = S(fast_f2nat(x), fast_f2nat(y));
+ if(SOLID(s)) break;
+ float floor = s->floor;
+ if(s->type==FHF) floor -= s->vdelta/4.0f;
+ float ceil = s->ceil;
+ if(s->type==CHF) ceil += s->vdelta/4.0f;
+ float rz = lz-((lz-bz)*(i/(float)steps));
+ if(rzceil) break;
+ v.x = x;
+ v.y = y;
+ v.z = rz;
+ x += dx/(float)steps;
+ y += dy/(float)steps;
+ i++;
+ };
+ return i>=steps;
+};
+
+bool enemylos(dynent *m, vec &v)
+{
+ v = m->o;
+ return los(m->o.x, m->o.y, m->o.z, m->enemy->o.x, m->enemy->o.y, m->enemy->o.z, v);
+};
+
+// monster AI is sequenced using transitions: they are in a particular state where
+// they execute a particular behaviour until the trigger time is hit, and then they
+// reevaluate their situation based on the current state, the environment etc., and
+// transition to the next state. Transition timeframes are parametrized by difficulty
+// level (skill), faster transitions means quicker decision making means tougher AI.
+
+void transition(dynent *m, int state, int moving, int n, int r) // n = at skill 0, n/2 = at skill 10, r = added random factor
+{
+ m->monsterstate = state;
+ m->move = moving;
+ n = n*130/100;
+ m->trigger = lastmillis+n-skill*(n/16)+rnd(r+1);
+};
+
+void normalise(dynent *m, float angle)
+{
+ while(m->yawyaw += 360.0f;
+ while(m->yaw>angle+180.0f) m->yaw -= 360.0f;
+};
+
+void monsteraction(dynent *m) // main AI thinking routine, called every frame for every monster
+{
+ if(m->enemy->state==CS_DEAD) { m->enemy = player1; m->anger = 0; };
+ normalise(m, m->targetyaw);
+ if(m->targetyaw>m->yaw) // slowly turn monster towards his target
+ {
+ m->yaw += curtime*0.5f;
+ if(m->targetyawyaw) m->yaw = m->targetyaw;
+ }
+ else
+ {
+ m->yaw -= curtime*0.5f;
+ if(m->targetyaw>m->yaw) m->yaw = m->targetyaw;
+ };
+
+ vdist(disttoenemy, vectoenemy, m->o, m->enemy->o);
+ m->pitch = atan2(m->enemy->o.z-m->o.z, disttoenemy)*180/PI;
+
+ if(m->blocked) // special case: if we run into scenery
+ {
+ m->blocked = false;
+ if(!rnd(20000/monstertypes[m->mtype].speed)) // try to jump over obstackle (rare)
+ {
+ m->jumpnext = true;
+ }
+ else if(m->triggermonsterstate!=M_HOME || !rnd(5))) // search for a way around (common)
+ {
+ m->targetyaw += 180+rnd(180); // patented "random walk" AI pathfinding (tm) ;)
+ transition(m, M_SEARCH, 1, 400, 1000);
+ };
+ };
+
+ float enemyyaw = -(float)atan2(m->enemy->o.x - m->o.x, m->enemy->o.y - m->o.y)/PI*180+180;
+
+ switch(m->monsterstate)
+ {
+ case M_PAIN:
+ case M_ATTACKING:
+ case M_SEARCH:
+ if(m->triggeryaw);
+ if(disttoenemy<8 // the better the angle to the player, the further the monster can see/hear
+ ||(disttoenemy<16 && angle<135)
+ ||(disttoenemy<32 && angle<90)
+ ||(disttoenemy<64 && angle<45)
+ || angle<10)
+ {
+ transition(m, M_HOME, 1, 500, 200);
+ playsound(S_GRUNT1+rnd(2), &m->o);
+ };
+ break;
+ };
+
+ case M_AIMING: // this state is the delay between wanting to shoot and actually firing
+ if(m->triggerlastaction = 0;
+ m->attacking = true;
+ shoot(m, m->attacktarget);
+ transition(m, M_ATTACKING, 0, 600, 0);
+ };
+ break;
+
+ case M_HOME: // monster has visual contact, heads straight for player and may want to shoot at any time
+ m->targetyaw = enemyyaw;
+ if(m->triggerenemy->state==CS_ALIVE) // get ready to fire
+ {
+ m->attacktarget = target;
+ transition(m, M_AIMING, 0, monstertypes[m->mtype].lag, 10);
+ }
+ else // track player some more
+ {
+ transition(m, M_HOME, 1, monstertypes[m->mtype].rate, 0);
+ };
+ };
+ };
+ break;
+ };
+
+ moveplayer(m, 1, false); // use physics to move monster
+};
+
+void monsterpain(dynent *m, int damage, dynent *d)
+{
+ if(d->monsterstate) // a monster hit us
+ {
+ if(m!=d) // guard for RL guys shooting themselves :)
+ {
+ m->anger++; // don't attack straight away, first get angry
+ int anger = m->mtype==d->mtype ? m->anger/2 : m->anger;
+ if(anger>=monstertypes[m->mtype].loyalty) m->enemy = d; // monster infight if very angry
+ };
+ }
+ else // player hit us
+ {
+ m->anger = 0;
+ m->enemy = d;
+ };
+ transition(m, M_PAIN, 0, monstertypes[m->mtype].pain,200); // in this state monster won't attack
+ if((m->health -= damage)<=0)
+ {
+ m->state = CS_DEAD;
+ m->lastaction = lastmillis;
+ numkilled++;
+ player1->frags = numkilled;
+ playsound(monstertypes[m->mtype].diesound, &m->o);
+ int remain = monstertotal-numkilled;
+ if(remain>0 && remain<=5) conoutf("only %d monster(s) remaining", remain);
+ }
+ else
+ {
+ playsound(monstertypes[m->mtype].painsound, &m->o);
+ };
+};
+
+void endsp(bool allkilled)
+{
+ conoutf(allkilled ? "you have cleared the map!" : "you reached the exit!");
+ conoutf("score: %d kills in %d seconds", numkilled, (lastmillis-mtimestart)/1000);
+ monstertotal = 0;
+ startintermission();
+};
+
+void monsterthink()
+{
+ if(m_dmsp && spawnremain && lastmillis>nextmonster)
+ {
+ if(spawnremain--==monstertotal) conoutf("The invasion has begun!");
+ nextmonster = lastmillis+1000;
+ spawnmonster();
+ };
+
+ if(monstertotal && !spawnremain && numkilled==monstertotal) endsp(true);
+
+ loopv(ents) // equivalent of player entity touch, but only teleports are used
+ {
+ entity &e = ents[i];
+ if(e.type!=TELEPORT) continue;
+ if(OUTBORD(e.x, e.y)) continue;
+ vec v = { e.x, e.y, S(e.x, e.y)->floor };
+ loopv(monsters) if(monsters[i]->state==CS_DEAD)
+ {
+ if(lastmillis-monsters[i]->lastaction<2000)
+ {
+ monsters[i]->move = 0;
+ moveplayer(monsters[i], 1, false);
+ };
+ }
+ else
+ {
+ v.z += monsters[i]->eyeheight;
+ vdist(dist, t, monsters[i]->o, v);
+ v.z -= monsters[i]->eyeheight;
+ if(dist<4) teleport((int)(&e-&ents[0]), monsters[i]);
+ };
+ };
+
+ loopv(monsters) if(monsters[i]->state==CS_ALIVE) monsteraction(monsters[i]);
+};
+
+void monsterrender()
+{
+ loopv(monsters) renderclient(monsters[i], false, monstertypes[monsters[i]->mtype].mdlname, monsters[i]->mtype==5, monstertypes[monsters[i]->mtype].mscale/10.0f);
+};
DELETED src/physics.cpp
Index: src/physics.cpp
==================================================================
--- src/physics.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-// physics.cpp: no physics books were hurt nor consulted in the construction of this code.
-// All physics computations and constants were invented on the fly and simply tweaked until
-// they "felt right", and have no basis in reality. Collision detection is simplistic but
-// very robust (uses discrete steps at fixed fps).
-
-#include "cube.h"
-
-bool plcollide(dynent *d, dynent *o, float &headspace, float &hi, float &lo) // collide with player or monster
-{
- if(o->state!=CS_ALIVE) return true;
- const float r = o->radius+d->radius;
- if(fabs(o->o.x-d->o.x)o.y-d->o.y)o.z-d->eyeheighto.z-o->eyeheight) { if(o->o.z-o->eyeheighto.z-o->eyeheight-1; }
- else if(o->o.z+o->aboveeye>lo) lo = o->o.z+o->aboveeye+1;
-
- if(fabs(o->o.z-d->o.z)aboveeye+d->eyeheight) return false;
- if(d->monsterstate) return false; // hack
- headspace = d->o.z-o->o.z-o->aboveeye-d->eyeheight;
- if(headspace<0) headspace = 10;
- };
- return true;
-};
-
-bool cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by, int &bs) // recursively collide with a mipmapped corner cube
-{
- sqr *w = wmip[mip];
- int sz = ssize>>mip;
- bool stest = SOLID(SWS(w, x+dx, y, sz)) && SOLID(SWS(w, x, y+dy, sz));
- mip++;
- x /= 2;
- y /= 2;
- if(SWS(wmip[mip], x, y, ssize>>mip)->type==CORNER)
- {
- bx = x<radius;
- if(fabs(e.x-d->o.x)o.y)floor+mmi.zoff+e.attr3);
- if(d->o.z-d->eyeheightlo) lo = mmz+mmi.h;
- };
- };
-};
-
-// all collision happens here
-// spawn is a dirty side effect used in spawning
-// drop & rise are supplied by the physics below to indicate gravity/push for current mini-timestep
-
-bool collide(dynent *d, bool spawn, float drop, float rise)
-{
- const float fx1 = d->o.x-d->radius; // figure out integer cube rectangle this entity covers in map
- const float fy1 = d->o.y-d->radius;
- const float fx2 = d->o.x+d->radius;
- const float fy2 = d->o.y+d->radius;
- const int x1 = fast_f2nat(fx1);
- const int y1 = fast_f2nat(fy1);
- const int x2 = fast_f2nat(fx2);
- const int y2 = fast_f2nat(fy2);
- float hi = 127, lo = -128;
- float minfloor = (d->monsterstate && !spawn && d->health>100) ? d->o.z-d->eyeheight-4.5f : -1000.0f; // big monsters are afraid of heights, unless angry :)
-
- for(int x = x1; x<=x2; x++) for(int y = y1; y<=y2; y++) // collide with map
- {
- if(OUTBORD(x,y)) return false;
- sqr *s = S(x,y);
- float ceil = s->ceil;
- float floor = s->floor;
- switch(s->type)
- {
- case SOLID:
- return false;
-
- case CORNER:
- {
- int bx = x, by = y, bs = 1;
- if(x==x1 && y==y1 && cornertest(0, x, y, -1, -1, bx, by, bs) && fx1-bx+fy1-by<=bs
- || x==x2 && y==y1 && cornertest(0, x, y, 1, -1, bx, by, bs) && fx2-bx>=fy1-by
- || x==x1 && y==y2 && cornertest(0, x, y, -1, 1, bx, by, bs) && fx1-bx<=fy2-by
- || x==x2 && y==y2 && cornertest(0, x, y, 1, 1, bx, by, bs) && fx2-bx+fy2-by>=bs)
- return false;
- break;
- };
-
- case FHF: // FIXME: too simplistic collision with slopes, makes it feels like tiny stairs
- floor -= (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
- break;
-
- case CHF:
- ceil += (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
-
- };
- if(ceillo) lo = floor;
- if(flooreyeheight+d->aboveeye) return false;
-
- float headspace = 10;
- loopv(players) // collide with other players
- {
- dynent *o = players[i];
- if(!o || o==d) continue;
- if(!plcollide(d, o, headspace, hi, lo)) return false;
- };
- if(d!=player1) if(!plcollide(d, player1, headspace, hi, lo)) return false;
- dvector &v = getmonsters();
- // this loop can be a performance bottleneck with many monster on a slow cpu,
- // should replace with a blockmap but seems mostly fast enough
- loopv(v) if(!vreject(d->o, v[i]->o, 7.0f) && d!=v[i] && !plcollide(d, v[i], headspace, hi, lo)) return false;
- headspace -= 0.01f;
-
- mmcollide(d, hi, lo); // collide with map models
-
- if(spawn)
- {
- d->o.z = lo+d->eyeheight; // just drop to floor (sideeffect)
- d->onfloor = true;
- }
- else
- {
- const float space = d->o.z-d->eyeheight-lo;
- if(space<0)
- {
- if(space>-0.01) d->o.z = lo+d->eyeheight; // stick on step
- else if(space>-1.26f) d->o.z += rise; // rise thru stair
- else return false;
- }
- else
- {
- d->o.z -= min(min(drop, space), headspace); // gravity
- };
-
- const float space2 = hi-(d->o.z+d->aboveeye);
- if(space2<0)
- {
- if(space2<-0.1) return false; // hack alert!
- d->o.z = hi-d->aboveeye; // glue to ceiling
- d->vel.z = 0; // cancel out jumping velocity
- };
-
- d->onfloor = d->o.z-d->eyeheight-lo<0.001f;
- };
- return true;
-}
-
-float rad(float x) { return x*3.14159f/180; };
-
-VARP(maxroll, 0, 3, 20);
-
-int physicsfraction = 0, physicsrepeat = 0;
-const int MINFRAMETIME = 20; // physics always simulated at 50fps or better
-
-void physicsframe() // optimally schedule physics frames inside the graphics frames
-{
- if(curtime>=MINFRAMETIME)
- {
- int faketime = curtime+physicsfraction;
- physicsrepeat = faketime/MINFRAMETIME;
- physicsfraction = faketime-physicsrepeat*MINFRAMETIME;
- }
- else
- {
- physicsrepeat = 1;
- };
-};
-
-// main physics routine, moves a player/monster for a curtime step
-// moveres indicated the physics precision (which is lower for monsters and multiplayer prediction)
-// local is false for multiplayer prediction
-
-void moveplayer(dynent *pl, int moveres, bool local, int curtime)
-{
- const bool water = hdr.waterlevel>pl->o.z-0.5f;
- const bool floating = (editmode && local) || pl->state==CS_EDITING;
-
- vec d; // vector of direction we ideally want to move in
-
- d.x = (float)(pl->move*cos(rad(pl->yaw-90)));
- d.y = (float)(pl->move*sin(rad(pl->yaw-90)));
- d.z = 0;
-
- if(floating || water)
- {
- d.x *= (float)cos(rad(pl->pitch));
- d.y *= (float)cos(rad(pl->pitch));
- d.z = (float)(pl->move*sin(rad(pl->pitch)));
- };
-
- d.x += (float)(pl->strafe*cos(rad(pl->yaw-180)));
- d.y += (float)(pl->strafe*sin(rad(pl->yaw-180)));
-
- const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed;
- const float friction = water ? 20.0f : (pl->onfloor || floating ? 6.0f : 30.0f);
-
- const float fpsfric = friction/curtime*20.0f;
-
- vmul(pl->vel, fpsfric-1); // slowly apply friction and direction to velocity, gives a smooth movement
- vadd(pl->vel, d);
- vdiv(pl->vel, fpsfric);
- d = pl->vel;
- vmul(d, speed); // d is now frametime based velocity vector
-
- pl->blocked = false;
- pl->moving = true;
-
- if(floating) // just apply velocity
- {
- vadd(pl->o, d);
- if(pl->jumpnext) { pl->jumpnext = false; pl->vel.z = 2; }
- }
- else // apply velocity with collision
- {
- if(pl->onfloor || water)
- {
- if(pl->jumpnext)
- {
- pl->jumpnext = false;
- pl->vel.z = 1.7f; // physics impulse upwards
- if(water) { pl->vel.x /= 8; pl->vel.y /= 8; }; // dampen velocity change even harder, gives correct water feel
- if(local) playsoundc(S_JUMP);
- else if(pl->monsterstate) playsound(S_JUMP, &pl->o);
- }
- else if(pl->timeinair>800) // if we land after long time must have been a high jump, make thud sound
- {
- if(local) playsoundc(S_LAND);
- else if(pl->monsterstate) playsound(S_LAND, &pl->o);
- };
- pl->timeinair = 0;
- }
- else
- {
- pl->timeinair += curtime;
- };
-
- const float gravity = 20;
- const float f = 1.0f/moveres;
- float dropf = ((gravity-1)+pl->timeinair/15.0f); // incorrect, but works fine
- if(water) { dropf = 5; pl->timeinair = 0; }; // float slowly down in water
- const float drop = dropf*curtime/gravity/100/moveres; // at high fps, gravity kicks in too fast
- const float rise = speed/moveres/1.2f; // extra smoothness when lifting up stairs
-
- loopi(moveres) // discrete steps collision detection & sliding
- {
- // try move forward
- pl->o.x += f*d.x;
- pl->o.y += f*d.y;
- pl->o.z += f*d.z;
- if(collide(pl, false, drop, rise)) continue;
- // player stuck, try slide along y axis
- pl->blocked = true;
- pl->o.x -= f*d.x;
- if(collide(pl, false, drop, rise)) { d.x = 0; continue; };
- pl->o.x += f*d.x;
- // still stuck, try x axis
- pl->o.y -= f*d.y;
- if(collide(pl, false, drop, rise)) { d.y = 0; continue; };
- pl->o.y += f*d.y;
- // try just dropping down
- pl->moving = false;
- pl->o.x -= f*d.x;
- pl->o.y -= f*d.y;
- if(collide(pl, false, drop, rise)) { d.y = d.x = 0; continue; };
- pl->o.z -= f*d.z;
- break;
- };
- };
-
- // detect wether player is outside map, used for skipping zbuffer clear mostly
-
- if(pl->o.x < 0 || pl->o.x >= ssize || pl->o.y <0 || pl->o.y > ssize)
- {
- pl->outsidemap = true;
- }
- else
- {
- sqr *s = S((int)pl->o.x, (int)pl->o.y);
- pl->outsidemap = SOLID(s)
- || pl->o.z < s->floor - (s->type==FHF ? s->vdelta/4 : 0)
- || pl->o.z > s->ceil + (s->type==CHF ? s->vdelta/4 : 0);
- };
-
- // automatically apply smooth roll when strafing
-
- if(pl->strafe==0)
- {
- pl->roll = pl->roll/(1+(float)sqrt((float)curtime)/25);
- }
- else
- {
- pl->roll += pl->strafe*curtime/-30.0f;
- if(pl->roll>maxroll) pl->roll = (float)maxroll;
- if(pl->roll<-maxroll) pl->roll = (float)-maxroll;
- };
-
- // play sounds on water transitions
-
- if(!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; }
- else if(pl->inwater && !water) playsound(S_SPLASH1, &pl->o);
- pl->inwater = water;
-};
-
-void moveplayer(dynent *pl, int moveres, bool local)
-{
- loopi(physicsrepeat) moveplayer(pl, moveres, local, i ? curtime/physicsrepeat : curtime-curtime/physicsrepeat*(physicsrepeat-1));
-};
-
ADDED src/physics.cxx
Index: src/physics.cxx
==================================================================
--- /dev/null
+++ src/physics.cxx
@@ -0,0 +1,323 @@
+// physics.cpp: no physics books were hurt nor consulted in the construction of this code.
+// All physics computations and constants were invented on the fly and simply tweaked until
+// they "felt right", and have no basis in reality. Collision detection is simplistic but
+// very robust (uses discrete steps at fixed fps).
+
+#include "cube.h"
+
+bool plcollide(dynent *d, dynent *o, float &headspace, float &hi, float &lo) // collide with player or monster
+{
+ if(o->state!=CS_ALIVE) return true;
+ const float r = o->radius+d->radius;
+ if(fabs(o->o.x-d->o.x)o.y-d->o.y)o.z-d->eyeheighto.z-o->eyeheight) { if(o->o.z-o->eyeheighto.z-o->eyeheight-1; }
+ else if(o->o.z+o->aboveeye>lo) lo = o->o.z+o->aboveeye+1;
+
+ if(fabs(o->o.z-d->o.z)aboveeye+d->eyeheight) return false;
+ if(d->monsterstate) return false; // hack
+ headspace = d->o.z-o->o.z-o->aboveeye-d->eyeheight;
+ if(headspace<0) headspace = 10;
+ };
+ return true;
+};
+
+bool cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by, int &bs) // recursively collide with a mipmapped corner cube
+{
+ sqr *w = wmip[mip];
+ int sz = ssize>>mip;
+ bool stest = SOLID(SWS(w, x+dx, y, sz)) && SOLID(SWS(w, x, y+dy, sz));
+ mip++;
+ x /= 2;
+ y /= 2;
+ if(SWS(wmip[mip], x, y, ssize>>mip)->type==CORNER)
+ {
+ bx = x<radius;
+ if(fabs(e.x-d->o.x)o.y)floor+mmi.zoff+e.attr3);
+ if(d->o.z-d->eyeheightlo) lo = mmz+mmi.h;
+ };
+ };
+};
+
+// all collision happens here
+// spawn is a dirty side effect used in spawning
+// drop & rise are supplied by the physics below to indicate gravity/push for current mini-timestep
+
+bool collide(dynent *d, bool spawn, float drop, float rise)
+{
+ const float fx1 = d->o.x-d->radius; // figure out integer cube rectangle this entity covers in map
+ const float fy1 = d->o.y-d->radius;
+ const float fx2 = d->o.x+d->radius;
+ const float fy2 = d->o.y+d->radius;
+ const int x1 = fast_f2nat(fx1);
+ const int y1 = fast_f2nat(fy1);
+ const int x2 = fast_f2nat(fx2);
+ const int y2 = fast_f2nat(fy2);
+ float hi = 127, lo = -128;
+ float minfloor = (d->monsterstate && !spawn && d->health>100) ? d->o.z-d->eyeheight-4.5f : -1000.0f; // big monsters are afraid of heights, unless angry :)
+
+ for(int x = x1; x<=x2; x++) for(int y = y1; y<=y2; y++) // collide with map
+ {
+ if(OUTBORD(x,y)) return false;
+ sqr *s = S(x,y);
+ float ceil = s->ceil;
+ float floor = s->floor;
+ switch(s->type)
+ {
+ case SOLID:
+ return false;
+
+ case CORNER:
+ {
+ int bx = x, by = y, bs = 1;
+ if(x==x1 && y==y1 && cornertest(0, x, y, -1, -1, bx, by, bs) && fx1-bx+fy1-by<=bs
+ || x==x2 && y==y1 && cornertest(0, x, y, 1, -1, bx, by, bs) && fx2-bx>=fy1-by
+ || x==x1 && y==y2 && cornertest(0, x, y, -1, 1, bx, by, bs) && fx1-bx<=fy2-by
+ || x==x2 && y==y2 && cornertest(0, x, y, 1, 1, bx, by, bs) && fx2-bx+fy2-by>=bs)
+ return false;
+ break;
+ };
+
+ case FHF: // FIXME: too simplistic collision with slopes, makes it feels like tiny stairs
+ floor -= (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
+ break;
+
+ case CHF:
+ ceil += (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
+
+ };
+ if(ceillo) lo = floor;
+ if(flooreyeheight+d->aboveeye) return false;
+
+ float headspace = 10;
+ loopv(players) // collide with other players
+ {
+ dynent *o = players[i];
+ if(!o || o==d) continue;
+ if(!plcollide(d, o, headspace, hi, lo)) return false;
+ };
+ if(d!=player1) if(!plcollide(d, player1, headspace, hi, lo)) return false;
+ dvector &v = getmonsters();
+ // this loop can be a performance bottleneck with many monster on a slow cpu,
+ // should replace with a blockmap but seems mostly fast enough
+ loopv(v) if(!vreject(d->o, v[i]->o, 7.0f) && d!=v[i] && !plcollide(d, v[i], headspace, hi, lo)) return false;
+ headspace -= 0.01f;
+
+ mmcollide(d, hi, lo); // collide with map models
+
+ if(spawn)
+ {
+ d->o.z = lo+d->eyeheight; // just drop to floor (sideeffect)
+ d->onfloor = true;
+ }
+ else
+ {
+ const float space = d->o.z-d->eyeheight-lo;
+ if(space<0)
+ {
+ if(space>-0.01) d->o.z = lo+d->eyeheight; // stick on step
+ else if(space>-1.26f) d->o.z += rise; // rise thru stair
+ else return false;
+ }
+ else
+ {
+ d->o.z -= min(min(drop, space), headspace); // gravity
+ };
+
+ const float space2 = hi-(d->o.z+d->aboveeye);
+ if(space2<0)
+ {
+ if(space2<-0.1) return false; // hack alert!
+ d->o.z = hi-d->aboveeye; // glue to ceiling
+ d->vel.z = 0; // cancel out jumping velocity
+ };
+
+ d->onfloor = d->o.z-d->eyeheight-lo<0.001f;
+ };
+ return true;
+}
+
+float rad(float x) { return x*3.14159f/180; };
+
+VARP(maxroll, 0, 3, 20);
+
+int physicsfraction = 0, physicsrepeat = 0;
+const int MINFRAMETIME = 20; // physics always simulated at 50fps or better
+
+void physicsframe() // optimally schedule physics frames inside the graphics frames
+{
+ if(curtime>=MINFRAMETIME)
+ {
+ int faketime = curtime+physicsfraction;
+ physicsrepeat = faketime/MINFRAMETIME;
+ physicsfraction = faketime-physicsrepeat*MINFRAMETIME;
+ }
+ else
+ {
+ physicsrepeat = 1;
+ };
+};
+
+// main physics routine, moves a player/monster for a curtime step
+// moveres indicated the physics precision (which is lower for monsters and multiplayer prediction)
+// local is false for multiplayer prediction
+
+void moveplayer(dynent *pl, int moveres, bool local, int curtime)
+{
+ const bool water = hdr.waterlevel>pl->o.z-0.5f;
+ const bool floating = (editmode && local) || pl->state==CS_EDITING;
+
+ vec d; // vector of direction we ideally want to move in
+
+ d.x = (float)(pl->move*cos(rad(pl->yaw-90)));
+ d.y = (float)(pl->move*sin(rad(pl->yaw-90)));
+ d.z = 0;
+
+ if(floating || water)
+ {
+ d.x *= (float)cos(rad(pl->pitch));
+ d.y *= (float)cos(rad(pl->pitch));
+ d.z = (float)(pl->move*sin(rad(pl->pitch)));
+ };
+
+ d.x += (float)(pl->strafe*cos(rad(pl->yaw-180)));
+ d.y += (float)(pl->strafe*sin(rad(pl->yaw-180)));
+
+ const float speed = curtime/(water ? 2000.0f : 1000.0f)*pl->maxspeed;
+ const float friction = water ? 20.0f : (pl->onfloor || floating ? 6.0f : 30.0f);
+
+ const float fpsfric = friction/curtime*20.0f;
+
+ vmul(pl->vel, fpsfric-1); // slowly apply friction and direction to velocity, gives a smooth movement
+ vadd(pl->vel, d);
+ vdiv(pl->vel, fpsfric);
+ d = pl->vel;
+ vmul(d, speed); // d is now frametime based velocity vector
+
+ pl->blocked = false;
+ pl->moving = true;
+
+ if(floating) // just apply velocity
+ {
+ vadd(pl->o, d);
+ if(pl->jumpnext) { pl->jumpnext = false; pl->vel.z = 2; }
+ }
+ else // apply velocity with collision
+ {
+ if(pl->onfloor || water)
+ {
+ if(pl->jumpnext)
+ {
+ pl->jumpnext = false;
+ pl->vel.z = 1.7f; // physics impulse upwards
+ if(water) { pl->vel.x /= 8; pl->vel.y /= 8; }; // dampen velocity change even harder, gives correct water feel
+ if(local) playsoundc(S_JUMP);
+ else if(pl->monsterstate) playsound(S_JUMP, &pl->o);
+ }
+ else if(pl->timeinair>800) // if we land after long time must have been a high jump, make thud sound
+ {
+ if(local) playsoundc(S_LAND);
+ else if(pl->monsterstate) playsound(S_LAND, &pl->o);
+ };
+ pl->timeinair = 0;
+ }
+ else
+ {
+ pl->timeinair += curtime;
+ };
+
+ const float gravity = 20;
+ const float f = 1.0f/moveres;
+ float dropf = ((gravity-1)+pl->timeinair/15.0f); // incorrect, but works fine
+ if(water) { dropf = 5; pl->timeinair = 0; }; // float slowly down in water
+ const float drop = dropf*curtime/gravity/100/moveres; // at high fps, gravity kicks in too fast
+ const float rise = speed/moveres/1.2f; // extra smoothness when lifting up stairs
+
+ loopi(moveres) // discrete steps collision detection & sliding
+ {
+ // try move forward
+ pl->o.x += f*d.x;
+ pl->o.y += f*d.y;
+ pl->o.z += f*d.z;
+ if(collide(pl, false, drop, rise)) continue;
+ // player stuck, try slide along y axis
+ pl->blocked = true;
+ pl->o.x -= f*d.x;
+ if(collide(pl, false, drop, rise)) { d.x = 0; continue; };
+ pl->o.x += f*d.x;
+ // still stuck, try x axis
+ pl->o.y -= f*d.y;
+ if(collide(pl, false, drop, rise)) { d.y = 0; continue; };
+ pl->o.y += f*d.y;
+ // try just dropping down
+ pl->moving = false;
+ pl->o.x -= f*d.x;
+ pl->o.y -= f*d.y;
+ if(collide(pl, false, drop, rise)) { d.y = d.x = 0; continue; };
+ pl->o.z -= f*d.z;
+ break;
+ };
+ };
+
+ // detect wether player is outside map, used for skipping zbuffer clear mostly
+
+ if(pl->o.x < 0 || pl->o.x >= ssize || pl->o.y <0 || pl->o.y > ssize)
+ {
+ pl->outsidemap = true;
+ }
+ else
+ {
+ sqr *s = S((int)pl->o.x, (int)pl->o.y);
+ pl->outsidemap = SOLID(s)
+ || pl->o.z < s->floor - (s->type==FHF ? s->vdelta/4 : 0)
+ || pl->o.z > s->ceil + (s->type==CHF ? s->vdelta/4 : 0);
+ };
+
+ // automatically apply smooth roll when strafing
+
+ if(pl->strafe==0)
+ {
+ pl->roll = pl->roll/(1+(float)sqrt((float)curtime)/25);
+ }
+ else
+ {
+ pl->roll += pl->strafe*curtime/-30.0f;
+ if(pl->roll>maxroll) pl->roll = (float)maxroll;
+ if(pl->roll<-maxroll) pl->roll = (float)-maxroll;
+ };
+
+ // play sounds on water transitions
+
+ if(!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; }
+ else if(pl->inwater && !water) playsound(S_SPLASH1, &pl->o);
+ pl->inwater = water;
+};
+
+void moveplayer(dynent *pl, int moveres, bool local)
+{
+ loopi(physicsrepeat) moveplayer(pl, moveres, local, i ? curtime/physicsrepeat : curtime-curtime/physicsrepeat*(physicsrepeat-1));
+};
+
DELETED src/rendercubes.cpp
Index: src/rendercubes.cpp
==================================================================
--- src/rendercubes.cpp
+++ /dev/null
@@ -1,359 +0,0 @@
-// rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills the vertex array for different cube surfaces.
-
-#include "cube.h"
-
-vertex *verts = NULL;
-int curvert;
-int curmaxverts = 10000;
-
-void setarraypointers()
-{
- glVertexPointer(3, GL_FLOAT, sizeof(vertex), &verts[0].x);
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), &verts[0].r);
- glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), &verts[0].u);
-};
-
-void reallocv()
-{
- verts = (vertex *)realloc(verts, (curmaxverts *= 2)*sizeof(vertex));
- curmaxverts -= 10;
- if(!verts) fatal("no vertex memory!");
- setarraypointers();
-};
-
-// generating the actual vertices is done dynamically every frame and sits at the
-// leaves of all these functions, and are part of the cpu bottleneck on really slow
-// machines, hence the macros.
-
-#define vertcheck() { if(curvert>=curmaxverts) reallocv(); }
-
-#define vertf(v1, v2, v3, ls, t1, t2) { vertex &v = verts[curvert++]; \
- v.u = t1; v.v = t2; \
- v.x = v1; v.y = v2; v.z = v3; \
- v.r = ls->r; v.g = ls->g; v.b = ls->b; v.a = 255; };
-
-#define vert(v1, v2, v3, ls, t1, t2) { vertf((float)(v1), (float)(v2), (float)(v3), ls, t1, t2); }
-
-int nquads;
-const float TEXTURESCALE = 32.0f;
-bool floorstrip = false, deltastrip = false;
-int oh, oy, ox, ogltex; // the o* vars are used by the stripification
-int ol3r, ol3g, ol3b, ol4r, ol4g, ol4b;
-int firstindex;
-bool showm = false;
-
-void showmip() { showm = !showm; };
-void mipstats(int a, int b, int c) { if(showm) conoutf("1x1/2x2/4x4: %d / %d / %d", a, b, c); };
-
-COMMAND(showmip, ARG_NONE);
-
-#define stripend() { if(floorstrip || deltastrip) { addstrip(ogltex, firstindex, curvert-firstindex); floorstrip = deltastrip = false; }; };
-void finishstrips() { stripend(); };
-
-sqr sbright, sdark;
-VAR(lighterror,1,8,100);
-
-void render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil) // floor/ceil quads
-{
- vertcheck();
- if(showm) { l3 = l1 = &sbright; l4 = l2 = &sdark; };
-
- int sx, sy;
- int gltex = lookuptexture(wtex, sx, sy);
- float xf = TEXTURESCALE/sx;
- float yf = TEXTURESCALE/sy;
- float xs = size*xf;
- float ys = size*yf;
- float xo = xf*x;
- float yo = yf*y;
-
- bool first = !floorstrip || y!=oy+size || ogltex!=gltex || h!=oh || x!=ox;
-
- if(first) // start strip here
- {
- stripend();
- firstindex = curvert;
- ogltex = gltex;
- oh = h;
- ox = x;
- floorstrip = true;
- if(isceil)
- {
- vert(x+size, h, y, l2, xo+xs, yo);
- vert(x, h, y, l1, xo, yo);
- }
- else
- {
- vert(x, h, y, l1, xo, yo);
- vert(x+size, h, y, l2, xo+xs, yo);
- };
- ol3r = l1->r;
- ol3g = l1->g;
- ol3b = l1->b;
- ol4r = l2->r;
- ol4g = l2->g;
- ol4b = l2->b;
- }
- else // continue strip
- {
- int lighterr = lighterror*2;
- if((abs(ol3r-l3->r)r)g)g)b)b)r;
- ol3g = l1->g;
- ol3b = l1->b;
- ol4r = l2->r;
- ol4g = l2->g;
- ol4b = l2->b;
- };
-
- if(isceil)
- {
- vertf((float)x+size, h3, (float)y+size, l3, xo+xs, yo+ys);
- vertf((float)x, h4, (float)y+size, l4, xo, yo+ys);
- }
- else
- {
- vertf((float)x, h4, (float)y+size, l4, xo, yo+ys);
- vertf((float)x+size, h3, (float)y+size, l3, xo+xs, yo+ys);
- };
-
- oy = y;
- nquads++;
-};
-
-void render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3, sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube
-{
- stripend();
- vertcheck();
-
- int sx, sy;
- int gltex = lookuptexture(h->ftex, sx, sy);
- float xf = TEXTURESCALE/sx;
- float yf = TEXTURESCALE/sy;
-
- vertf((float)x1, h->floor, (float)y1, l1, xf*x1, yf*y1);
- vertf((float)x2, h->floor, (float)y2, l2, xf*x2, yf*y2);
- vertf((float)x3, h->floor, (float)y3, l3, xf*x3, yf*y3);
- addstrip(gltex, curvert-3, 3);
-
- gltex = lookuptexture(h->ctex, sx, sy);
- xf = TEXTURESCALE/sx;
- yf = TEXTURESCALE/sy;
-
- vertf((float)x3, h->ceil, (float)y3, l3, xf*x3, yf*y3);
- vertf((float)x2, h->ceil, (float)y2, l2, xf*x2, yf*y2);
- vertf((float)x1, h->ceil, (float)y1, l1, xf*x1, yf*y1);
- addstrip(gltex, curvert-3, 3);
- nquads++;
-};
-
-void render_tris(int x, int y, int size, bool topleft,
- sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v)
-{
- if(topleft)
- {
- if(h1) render_2tris(h1, s, x+size, y+size, x, y+size, x, y, u, v, s);
- if(h2) render_2tris(h2, s, x, y, x+size, y, x+size, y+size, s, t, v);
- }
- else
- {
- if(h1) render_2tris(h1, s, x, y, x+size, y, x, y+size, s, t, u);
- if(h2) render_2tris(h2, s, x+size, y, x+size, y+size, x, y+size, t, u, v);
- };
-};
-
-void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool flip) // wall quads
-{
- stripend();
- vertcheck();
- if(showm) { l1 = &sbright; l2 = &sdark; };
-
- int sx, sy;
- int gltex = lookuptexture(wtex, sx, sy);
- float xf = TEXTURESCALE/sx;
- float yf = TEXTURESCALE/sy;
- float xs = size*xf;
- float xo = xf*(x1==x2 ? min(y1,y2) : min(x1,x2));
-
- if(!flip)
- {
- vertf((float)x2, ceil2, (float)y2, l2, xo+xs, -yf*ceil2);
- vertf((float)x1, ceil1, (float)y1, l1, xo, -yf*ceil1);
- vertf((float)x2, floor2, (float)y2, l2, xo+xs, -floor2*yf);
- vertf((float)x1, floor1, (float)y1, l1, xo, -floor1*yf);
- }
- else
- {
- vertf((float)x1, ceil1, (float)y1, l1, xo, -yf*ceil1);
- vertf((float)x2, ceil2, (float)y2, l2, xo+xs, -yf*ceil2);
- vertf((float)x1, floor1, (float)y1, l1, xo, -floor1*yf);
- vertf((float)x2, floor2, (float)y2, l2, xo+xs, -floor2*yf);
- };
-
- nquads++;
- addstrip(gltex, curvert-4, 4);
-};
-
-int wx1, wy1, wx2, wy2;
-
-VAR(watersubdiv, 1, 4, 64);
-VARF(waterlevel, -128, -128, 127, if(!noteditmode()) hdr.waterlevel = waterlevel);
-
-inline void vertw(int v1, float v2, int v3, sqr *c, float t1, float t2, float t)
-{
- vertcheck();
- vertf((float)v1, v2-(float)sin(v1*v3*0.1+t)*0.2f, (float)v3, c, t1, t2);
-};
-
-inline float dx(float x) { return x+(float)sin(x*2+lastmillis/1000.0f)*0.04f; };
-inline float dy(float x) { return x+(float)sin(x*2+lastmillis/900.0f+PI/5)*0.05f; };
-
-// renders water for bounding rect area that contains water... simple but very inefficient
-
-int renderwater(float hf)
-{
- if(wx1<0) return nquads;
-
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_SRC_COLOR);
- int sx, sy;
- glBindTexture(GL_TEXTURE_2D, lookuptexture(DEFAULT_LIQUID, sx, sy));
-
- wx1 &= ~(watersubdiv-1);
- wy1 &= ~(watersubdiv-1);
-
- float xf = TEXTURESCALE/sx;
- float yf = TEXTURESCALE/sy;
- float xs = watersubdiv*xf;
- float ys = watersubdiv*yf;
- float t1 = lastmillis/300.0f;
- float t2 = lastmillis/4000.0f;
-
- sqr dl;
- dl.r = dl.g = dl.b = 255;
-
- for(int xx = wx1; xxwx2) wx2 = x2;
- if(y2>wy2) wy2 = y2;
- };
-};
-
-void resetcubes()
-{
- if(!verts) reallocv();
- floorstrip = deltastrip = false;
- wx1 = -1;
- nquads = 0;
- sbright.r = sbright.g = sbright.b = 255;
- sdark.r = sdark.g = sdark.b = 0;
-};
-
-
ADDED src/rendercubes.cxx
Index: src/rendercubes.cxx
==================================================================
--- /dev/null
+++ src/rendercubes.cxx
@@ -0,0 +1,359 @@
+// rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills the vertex array for different cube surfaces.
+
+#include "cube.h"
+
+vertex *verts = NULL;
+int curvert;
+int curmaxverts = 10000;
+
+void setarraypointers()
+{
+ glVertexPointer(3, GL_FLOAT, sizeof(vertex), &verts[0].x);
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), &verts[0].r);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), &verts[0].u);
+};
+
+void reallocv()
+{
+ verts = (vertex *)realloc(verts, (curmaxverts *= 2)*sizeof(vertex));
+ curmaxverts -= 10;
+ if(!verts) fatal("no vertex memory!");
+ setarraypointers();
+};
+
+// generating the actual vertices is done dynamically every frame and sits at the
+// leaves of all these functions, and are part of the cpu bottleneck on really slow
+// machines, hence the macros.
+
+#define vertcheck() { if(curvert>=curmaxverts) reallocv(); }
+
+#define vertf(v1, v2, v3, ls, t1, t2) { vertex &v = verts[curvert++]; \
+ v.u = t1; v.v = t2; \
+ v.x = v1; v.y = v2; v.z = v3; \
+ v.r = ls->r; v.g = ls->g; v.b = ls->b; v.a = 255; };
+
+#define vert(v1, v2, v3, ls, t1, t2) { vertf((float)(v1), (float)(v2), (float)(v3), ls, t1, t2); }
+
+int nquads;
+const float TEXTURESCALE = 32.0f;
+bool floorstrip = false, deltastrip = false;
+int oh, oy, ox, ogltex; // the o* vars are used by the stripification
+int ol3r, ol3g, ol3b, ol4r, ol4g, ol4b;
+int firstindex;
+bool showm = false;
+
+void showmip() { showm = !showm; };
+void mipstats(int a, int b, int c) { if(showm) conoutf("1x1/2x2/4x4: %d / %d / %d", a, b, c); };
+
+COMMAND(showmip, ARG_NONE);
+
+#define stripend() { if(floorstrip || deltastrip) { addstrip(ogltex, firstindex, curvert-firstindex); floorstrip = deltastrip = false; }; };
+void finishstrips() { stripend(); };
+
+sqr sbright, sdark;
+VAR(lighterror,1,8,100);
+
+void render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil) // floor/ceil quads
+{
+ vertcheck();
+ if(showm) { l3 = l1 = &sbright; l4 = l2 = &sdark; };
+
+ int sx, sy;
+ int gltex = lookuptexture(wtex, sx, sy);
+ float xf = TEXTURESCALE/sx;
+ float yf = TEXTURESCALE/sy;
+ float xs = size*xf;
+ float ys = size*yf;
+ float xo = xf*x;
+ float yo = yf*y;
+
+ bool first = !floorstrip || y!=oy+size || ogltex!=gltex || h!=oh || x!=ox;
+
+ if(first) // start strip here
+ {
+ stripend();
+ firstindex = curvert;
+ ogltex = gltex;
+ oh = h;
+ ox = x;
+ floorstrip = true;
+ if(isceil)
+ {
+ vert(x+size, h, y, l2, xo+xs, yo);
+ vert(x, h, y, l1, xo, yo);
+ }
+ else
+ {
+ vert(x, h, y, l1, xo, yo);
+ vert(x+size, h, y, l2, xo+xs, yo);
+ };
+ ol3r = l1->r;
+ ol3g = l1->g;
+ ol3b = l1->b;
+ ol4r = l2->r;
+ ol4g = l2->g;
+ ol4b = l2->b;
+ }
+ else // continue strip
+ {
+ int lighterr = lighterror*2;
+ if((abs(ol3r-l3->r)r)g)g)b)b)r;
+ ol3g = l1->g;
+ ol3b = l1->b;
+ ol4r = l2->r;
+ ol4g = l2->g;
+ ol4b = l2->b;
+ };
+
+ if(isceil)
+ {
+ vertf((float)x+size, h3, (float)y+size, l3, xo+xs, yo+ys);
+ vertf((float)x, h4, (float)y+size, l4, xo, yo+ys);
+ }
+ else
+ {
+ vertf((float)x, h4, (float)y+size, l4, xo, yo+ys);
+ vertf((float)x+size, h3, (float)y+size, l3, xo+xs, yo+ys);
+ };
+
+ oy = y;
+ nquads++;
+};
+
+void render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3, sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube
+{
+ stripend();
+ vertcheck();
+
+ int sx, sy;
+ int gltex = lookuptexture(h->ftex, sx, sy);
+ float xf = TEXTURESCALE/sx;
+ float yf = TEXTURESCALE/sy;
+
+ vertf((float)x1, h->floor, (float)y1, l1, xf*x1, yf*y1);
+ vertf((float)x2, h->floor, (float)y2, l2, xf*x2, yf*y2);
+ vertf((float)x3, h->floor, (float)y3, l3, xf*x3, yf*y3);
+ addstrip(gltex, curvert-3, 3);
+
+ gltex = lookuptexture(h->ctex, sx, sy);
+ xf = TEXTURESCALE/sx;
+ yf = TEXTURESCALE/sy;
+
+ vertf((float)x3, h->ceil, (float)y3, l3, xf*x3, yf*y3);
+ vertf((float)x2, h->ceil, (float)y2, l2, xf*x2, yf*y2);
+ vertf((float)x1, h->ceil, (float)y1, l1, xf*x1, yf*y1);
+ addstrip(gltex, curvert-3, 3);
+ nquads++;
+};
+
+void render_tris(int x, int y, int size, bool topleft,
+ sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v)
+{
+ if(topleft)
+ {
+ if(h1) render_2tris(h1, s, x+size, y+size, x, y+size, x, y, u, v, s);
+ if(h2) render_2tris(h2, s, x, y, x+size, y, x+size, y+size, s, t, v);
+ }
+ else
+ {
+ if(h1) render_2tris(h1, s, x, y, x+size, y, x, y+size, s, t, u);
+ if(h2) render_2tris(h2, s, x+size, y, x+size, y+size, x, y+size, t, u, v);
+ };
+};
+
+void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool flip) // wall quads
+{
+ stripend();
+ vertcheck();
+ if(showm) { l1 = &sbright; l2 = &sdark; };
+
+ int sx, sy;
+ int gltex = lookuptexture(wtex, sx, sy);
+ float xf = TEXTURESCALE/sx;
+ float yf = TEXTURESCALE/sy;
+ float xs = size*xf;
+ float xo = xf*(x1==x2 ? min(y1,y2) : min(x1,x2));
+
+ if(!flip)
+ {
+ vertf((float)x2, ceil2, (float)y2, l2, xo+xs, -yf*ceil2);
+ vertf((float)x1, ceil1, (float)y1, l1, xo, -yf*ceil1);
+ vertf((float)x2, floor2, (float)y2, l2, xo+xs, -floor2*yf);
+ vertf((float)x1, floor1, (float)y1, l1, xo, -floor1*yf);
+ }
+ else
+ {
+ vertf((float)x1, ceil1, (float)y1, l1, xo, -yf*ceil1);
+ vertf((float)x2, ceil2, (float)y2, l2, xo+xs, -yf*ceil2);
+ vertf((float)x1, floor1, (float)y1, l1, xo, -floor1*yf);
+ vertf((float)x2, floor2, (float)y2, l2, xo+xs, -floor2*yf);
+ };
+
+ nquads++;
+ addstrip(gltex, curvert-4, 4);
+};
+
+int wx1, wy1, wx2, wy2;
+
+VAR(watersubdiv, 1, 4, 64);
+VARF(waterlevel, -128, -128, 127, if(!noteditmode()) hdr.waterlevel = waterlevel);
+
+inline void vertw(int v1, float v2, int v3, sqr *c, float t1, float t2, float t)
+{
+ vertcheck();
+ vertf((float)v1, v2-(float)sin(v1*v3*0.1+t)*0.2f, (float)v3, c, t1, t2);
+};
+
+inline float dx(float x) { return x+(float)sin(x*2+lastmillis/1000.0f)*0.04f; };
+inline float dy(float x) { return x+(float)sin(x*2+lastmillis/900.0f+PI/5)*0.05f; };
+
+// renders water for bounding rect area that contains water... simple but very inefficient
+
+int renderwater(float hf)
+{
+ if(wx1<0) return nquads;
+
+ glDepthMask(GL_FALSE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_SRC_COLOR);
+ int sx, sy;
+ glBindTexture(GL_TEXTURE_2D, lookuptexture(DEFAULT_LIQUID, sx, sy));
+
+ wx1 &= ~(watersubdiv-1);
+ wy1 &= ~(watersubdiv-1);
+
+ float xf = TEXTURESCALE/sx;
+ float yf = TEXTURESCALE/sy;
+ float xs = watersubdiv*xf;
+ float ys = watersubdiv*yf;
+ float t1 = lastmillis/300.0f;
+ float t2 = lastmillis/4000.0f;
+
+ sqr dl;
+ dl.r = dl.g = dl.b = 255;
+
+ for(int xx = wx1; xxwx2) wx2 = x2;
+ if(y2>wy2) wy2 = y2;
+ };
+};
+
+void resetcubes()
+{
+ if(!verts) reallocv();
+ floorstrip = deltastrip = false;
+ wx1 = -1;
+ nquads = 0;
+ sbright.r = sbright.g = sbright.b = 255;
+ sdark.r = sdark.g = sdark.b = 0;
+};
+
+
DELETED src/renderextras.cpp
Index: src/renderextras.cpp
==================================================================
--- src/renderextras.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-// renderextras.cpp: misc gl render code and the HUD
-
-#include "cube.h"
-
-void line(int x1, int y1, float z1, int x2, int y2, float z2)
-{
- glBegin(GL_POLYGON);
- glVertex3f((float)x1, z1, (float)y1);
- glVertex3f((float)x1, z1, y1+0.01f);
- glVertex3f((float)x2, z2, y2+0.01f);
- glVertex3f((float)x2, z2, (float)y2);
- glEnd();
- xtraverts += 4;
-};
-
-void linestyle(float width, int r, int g, int b)
-{
- glLineWidth(width);
- glColor3ub(r,g,b);
-};
-
-void box(block &b, float z1, float z2, float z3, float z4)
-{
- glBegin(GL_POLYGON);
- glVertex3f((float)b.x, z1, (float)b.y);
- glVertex3f((float)b.x+b.xs, z2, (float)b.y);
- glVertex3f((float)b.x+b.xs, z3, (float)b.y+b.ys);
- glVertex3f((float)b.x, z4, (float)b.y+b.ys);
- glEnd();
- xtraverts += 4;
-};
-
-void dot(int x, int y, float z)
-{
- const float DOF = 0.1f;
- glBegin(GL_POLYGON);
- glVertex3f(x-DOF, (float)z, y-DOF);
- glVertex3f(x+DOF, (float)z, y-DOF);
- glVertex3f(x+DOF, (float)z, y+DOF);
- glVertex3f(x-DOF, (float)z, y+DOF);
- glEnd();
- xtraverts += 4;
-};
-
-void blendbox(int x1, int y1, int x2, int y2, bool border)
-{
- glDepthMask(GL_FALSE);
- glDisable(GL_TEXTURE_2D);
- glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
- glBegin(GL_QUADS);
- if(border) glColor3d(0.5, 0.3, 0.4);
- else glColor3d(1.0, 1.0, 1.0);
- glVertex2i(x1, y1);
- glVertex2i(x2, y1);
- glVertex2i(x2, y2);
- glVertex2i(x1, y2);
- glEnd();
- glDisable(GL_BLEND);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- glBegin(GL_POLYGON);
- glColor3d(0.2, 0.7, 0.4);
- glVertex2i(x1, y1);
- glVertex2i(x2, y1);
- glVertex2i(x2, y2);
- glVertex2i(x1, y2);
- glEnd();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- xtraverts += 8;
- glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
- glDepthMask(GL_TRUE);
-};
-
-const int MAXSPHERES = 50;
-struct sphere { vec o; float size, max; int type; sphere *next; };
-sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL;
-bool sinit = false;
-
-void newsphere(vec &o, float max, int type)
-{
- if(!sinit)
- {
- loopi(MAXSPHERES)
- {
- spheres[i].next = sempty;
- sempty = &spheres[i];
- };
- sinit = true;
- };
- if(sempty)
- {
- sphere *p = sempty;
- sempty = p->next;
- p->o = o;
- p->max = max;
- p->size = 1;
- p->type = type;
- p->next = slist;
- slist = p;
- };
-};
-
-void renderspheres(int time)
-{
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glBindTexture(GL_TEXTURE_2D, 4);
-
- for(sphere *p, **pp = &slist; p = *pp;)
- {
- glPushMatrix();
- float size = p->size/p->max;
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f-size);
- glTranslatef(p->o.x, p->o.z, p->o.y);
- glRotatef(lastmillis/5.0f, 1, 1, 1);
- glScalef(p->size, p->size, p->size);
- glCallList(1);
- glScalef(0.8f, 0.8f, 0.8f);
- glCallList(1);
- glPopMatrix();
- xtraverts += 12*6*2;
-
- if(p->size>p->max)
- {
- *pp = p->next;
- p->next = sempty;
- sempty = p;
- }
- else
- {
- p->size += time/100.0f;
- pp = &p->next;
- };
- };
-
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
-};
-
-string closeent;
-char *entnames[] =
-{
- "none?", "light", "playerstart",
- "shells", "bullets", "rockets", "riflerounds",
- "health", "healthboost", "greenarmour", "yellowarmour", "quaddamage",
- "teleport", "teledest",
- "mapmodel", "monster", "trigger", "jumppad",
- "?", "?", "?", "?", "?",
-};
-
-void renderents() // show sparkly thingies for map entities in edit mode
-{
- closeent[0] = 0;
- if(!editmode) return;
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type==NOTUSED) continue;
- vec v = { e.x, e.y, e.z };
- particle_splash(2, 2, 40, v);
- };
- int e = closestent();
- if(e>=0)
- {
- entity &c = ents[e];
- sprintf_s(closeent)("closest entity = %s (%d, %d, %d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar("selxs"), getvar("selys"));
- };
-};
-
-void loadsky(char *basename)
-{
- static string lastsky = "";
- if(strcmp(lastsky, basename)==0) return;
- char *side[] = { "ft", "bk", "lf", "rt", "dn", "up" };
- int texnum = 14;
- loopi(6)
- {
- sprintf_sd(name)("packages/%s_%s.jpg", basename, side[i]);
- int xs, ys;
- if(!installtex(texnum+i, path(name), xs, ys, true)) conoutf("could not load sky textures");
- };
- strcpy_s(lastsky, basename);
-};
-
-COMMAND(loadsky, ARG_1STR);
-
-float cursordepth = 0.9f;
-GLint viewport[4];
-GLdouble mm[16], pm[16];
-vec worldpos;
-
-void readmatrices()
-{
- glGetIntegerv(GL_VIEWPORT, viewport);
- glGetDoublev(GL_MODELVIEW_MATRIX, mm);
- glGetDoublev(GL_PROJECTION_MATRIX, pm);
-};
-
-// stupid function to cater for stupid ATI linux drivers that return incorrect depth values
-
-float depthcorrect(float d)
-{
- return (d<=1/256.0f) ? d*256 : d;
-};
-
-// find out the 3d target of the crosshair in the world easily and very acurately.
-// sadly many very old cards and drivers appear to fuck up on glReadPixels() and give false
-// coordinates, making shooting and such impossible.
-// also hits map entities which is unwanted.
-// could be replaced by a more acurate version of monster.cpp los() if needed
-
-void readdepth(int w, int h)
-{
- glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cursordepth);
- double worldx = 0, worldy = 0, worldz = 0;
- gluUnProject(w/2, h/2, depthcorrect(cursordepth), mm, pm, viewport, &worldx, &worldz, &worldy);
- worldpos.x = (float)worldx;
- worldpos.y = (float)worldy;
- worldpos.z = (float)worldz;
- vec r = { (float)mm[0], (float)mm[4], (float)mm[8] };
- vec u = { (float)mm[1], (float)mm[5], (float)mm[9] };
- setorient(r, u);
-};
-
-void drawicon(float tx, float ty, int x, int y)
-{
- glBindTexture(GL_TEXTURE_2D, 5);
- glBegin(GL_QUADS);
- tx /= 192;
- ty /= 192;
- float o = 1/3.0f;
- int s = 120;
- glTexCoord2f(tx, ty); glVertex2i(x, y);
- glTexCoord2f(tx+o, ty); glVertex2i(x+s, y);
- glTexCoord2f(tx+o, ty+o); glVertex2i(x+s, y+s);
- glTexCoord2f(tx, ty+o); glVertex2i(x, y+s);
- glEnd();
- xtraverts += 4;
-};
-
-void invertperspective()
-{
- // This only generates a valid inverse matrix for matrices generated by gluPerspective()
- GLdouble inv[16];
- memset(inv, 0, sizeof(inv));
-
- inv[0*4+0] = 1.0/pm[0*4+0];
- inv[1*4+1] = 1.0/pm[1*4+1];
- inv[2*4+3] = 1.0/pm[3*4+2];
- inv[3*4+2] = -1.0;
- inv[3*4+3] = pm[2*4+2]/pm[3*4+2];
-
- glLoadMatrixd(inv);
-};
-
-VARP(crosshairsize, 0, 15, 50);
-
-int dblend = 0;
-void damageblend(int n) { dblend += n; };
-
-VAR(hidestats, 0, 0, 1);
-VARP(crosshairfx, 0, 1, 1);
-
-void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater)
-{
- readmatrices();
- if(editmode)
- {
- if(cursordepth==1.0f) worldpos = player1->o;
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- cursorupdate();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- };
-
- glDisable(GL_DEPTH_TEST);
- invertperspective();
- glPushMatrix();
- glOrtho(0, VIRTW, VIRTH, 0, -1, 1);
- glEnable(GL_BLEND);
-
- glDepthMask(GL_FALSE);
-
- if(dblend || underwater)
- {
- glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
- glBegin(GL_QUADS);
- if(dblend) glColor3d(0.0f, 0.9f, 0.9f);
- else glColor3d(0.9f, 0.5f, 0.0f);
- glVertex2i(0, 0);
- glVertex2i(VIRTW, 0);
- glVertex2i(VIRTW, VIRTH);
- glVertex2i(0, VIRTH);
- glEnd();
- dblend -= curtime/3;
- if(dblend<0) dblend = 0;
- };
-
- glEnable(GL_TEXTURE_2D);
-
- char *command = getcurcommand();
- char *player = playerincrosshair();
- if(command) draw_textf("> %s_", 20, 1570, 2, command);
- else if(closeent[0]) draw_text(closeent, 20, 1570, 2);
- else if(player) draw_text(player, 20, 1570, 2);
-
- renderscores();
- if(!rendermenu())
- {
- glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
- glBindTexture(GL_TEXTURE_2D, 1);
- glBegin(GL_QUADS);
- glColor3ub(255,255,255);
- if(crosshairfx)
- {
- if(player1->gunwait) glColor3ub(128,128,128);
- else if(player1->health<=25) glColor3ub(255,0,0);
- else if(player1->health<=50) glColor3ub(255,128,0);
- };
- float chsize = (float)crosshairsize;
- glTexCoord2d(0.0, 0.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 - chsize);
- glTexCoord2d(1.0, 0.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 - chsize);
- glTexCoord2d(1.0, 1.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 + chsize);
- glTexCoord2d(0.0, 1.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 + chsize);
- glEnd();
- };
-
- glPopMatrix();
-
- glPushMatrix();
- glOrtho(0, VIRTW*4/3, VIRTH*4/3, 0, -1, 1);
- renderconsole();
-
- if(!hidestats)
- {
- glPopMatrix();
- glPushMatrix();
- glOrtho(0, VIRTW*3/2, VIRTH*3/2, 0, -1, 1);
- draw_textf("fps %d", 3200, 2390, 2, curfps);
- draw_textf("wqd %d", 3200, 2460, 2, nquads);
- draw_textf("wvt %d", 3200, 2530, 2, curvert);
- draw_textf("evt %d", 3200, 2600, 2, xtraverts);
- };
-
- glPopMatrix();
-
- if(player1->state==CS_ALIVE)
- {
- glPushMatrix();
- glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1);
- draw_textf("%d", 90, 827, 2, player1->health);
- if(player1->armour) draw_textf("%d", 390, 827, 2, player1->armour);
- draw_textf("%d", 690, 827, 2, player1->ammo[player1->gunselect]);
- glPopMatrix();
- glPushMatrix();
- glOrtho(0, VIRTW, VIRTH, 0, -1, 1);
- glDisable(GL_BLEND);
- drawicon(128, 128, 20, 1650);
- if(player1->armour) drawicon((float)(player1->armourtype*64), 0, 620, 1650);
- int g = player1->gunselect;
- int r = 64;
- if(g>2) { g -= 3; r = 128; };
- drawicon((float)(g*64), (float)r, 1220, 1650);
- glPopMatrix();
- };
-
- glDepthMask(GL_TRUE);
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
- glEnable(GL_DEPTH_TEST);
-};
-
ADDED src/renderextras.cxx
Index: src/renderextras.cxx
==================================================================
--- /dev/null
+++ src/renderextras.cxx
@@ -0,0 +1,372 @@
+// renderextras.cpp: misc gl render code and the HUD
+
+#include "cube.h"
+
+void line(int x1, int y1, float z1, int x2, int y2, float z2)
+{
+ glBegin(GL_POLYGON);
+ glVertex3f((float)x1, z1, (float)y1);
+ glVertex3f((float)x1, z1, y1+0.01f);
+ glVertex3f((float)x2, z2, y2+0.01f);
+ glVertex3f((float)x2, z2, (float)y2);
+ glEnd();
+ xtraverts += 4;
+};
+
+void linestyle(float width, int r, int g, int b)
+{
+ glLineWidth(width);
+ glColor3ub(r,g,b);
+};
+
+void box(block &b, float z1, float z2, float z3, float z4)
+{
+ glBegin(GL_POLYGON);
+ glVertex3f((float)b.x, z1, (float)b.y);
+ glVertex3f((float)b.x+b.xs, z2, (float)b.y);
+ glVertex3f((float)b.x+b.xs, z3, (float)b.y+b.ys);
+ glVertex3f((float)b.x, z4, (float)b.y+b.ys);
+ glEnd();
+ xtraverts += 4;
+};
+
+void dot(int x, int y, float z)
+{
+ const float DOF = 0.1f;
+ glBegin(GL_POLYGON);
+ glVertex3f(x-DOF, (float)z, y-DOF);
+ glVertex3f(x+DOF, (float)z, y-DOF);
+ glVertex3f(x+DOF, (float)z, y+DOF);
+ glVertex3f(x-DOF, (float)z, y+DOF);
+ glEnd();
+ xtraverts += 4;
+};
+
+void blendbox(int x1, int y1, int x2, int y2, bool border)
+{
+ glDepthMask(GL_FALSE);
+ glDisable(GL_TEXTURE_2D);
+ glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+ glBegin(GL_QUADS);
+ if(border) glColor3d(0.5, 0.3, 0.4);
+ else glColor3d(1.0, 1.0, 1.0);
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y1);
+ glVertex2i(x2, y2);
+ glVertex2i(x1, y2);
+ glEnd();
+ glDisable(GL_BLEND);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glBegin(GL_POLYGON);
+ glColor3d(0.2, 0.7, 0.4);
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y1);
+ glVertex2i(x2, y2);
+ glVertex2i(x1, y2);
+ glEnd();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ xtraverts += 8;
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glDepthMask(GL_TRUE);
+};
+
+const int MAXSPHERES = 50;
+struct sphere { vec o; float size, max; int type; sphere *next; };
+sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL;
+bool sinit = false;
+
+void newsphere(vec &o, float max, int type)
+{
+ if(!sinit)
+ {
+ loopi(MAXSPHERES)
+ {
+ spheres[i].next = sempty;
+ sempty = &spheres[i];
+ };
+ sinit = true;
+ };
+ if(sempty)
+ {
+ sphere *p = sempty;
+ sempty = p->next;
+ p->o = o;
+ p->max = max;
+ p->size = 1;
+ p->type = type;
+ p->next = slist;
+ slist = p;
+ };
+};
+
+void renderspheres(int time)
+{
+ glDepthMask(GL_FALSE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ glBindTexture(GL_TEXTURE_2D, 4);
+
+ for(sphere *p, **pp = &slist; p = *pp;)
+ {
+ glPushMatrix();
+ float size = p->size/p->max;
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f-size);
+ glTranslatef(p->o.x, p->o.z, p->o.y);
+ glRotatef(lastmillis/5.0f, 1, 1, 1);
+ glScalef(p->size, p->size, p->size);
+ glCallList(1);
+ glScalef(0.8f, 0.8f, 0.8f);
+ glCallList(1);
+ glPopMatrix();
+ xtraverts += 12*6*2;
+
+ if(p->size>p->max)
+ {
+ *pp = p->next;
+ p->next = sempty;
+ sempty = p;
+ }
+ else
+ {
+ p->size += time/100.0f;
+ pp = &p->next;
+ };
+ };
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+};
+
+string closeent;
+char *entnames[] =
+{
+ "none?", "light", "playerstart",
+ "shells", "bullets", "rockets", "riflerounds",
+ "health", "healthboost", "greenarmour", "yellowarmour", "quaddamage",
+ "teleport", "teledest",
+ "mapmodel", "monster", "trigger", "jumppad",
+ "?", "?", "?", "?", "?",
+};
+
+void renderents() // show sparkly thingies for map entities in edit mode
+{
+ closeent[0] = 0;
+ if(!editmode) return;
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type==NOTUSED) continue;
+ vec v = { e.x, e.y, e.z };
+ particle_splash(2, 2, 40, v);
+ };
+ int e = closestent();
+ if(e>=0)
+ {
+ entity &c = ents[e];
+ sprintf_s(closeent)("closest entity = %s (%d, %d, %d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar("selxs"), getvar("selys"));
+ };
+};
+
+void loadsky(char *basename)
+{
+ static string lastsky = "";
+ if(strcmp(lastsky, basename)==0) return;
+ char *side[] = { "ft", "bk", "lf", "rt", "dn", "up" };
+ int texnum = 14;
+ loopi(6)
+ {
+ sprintf_sd(name)("packages/%s_%s.jpg", basename, side[i]);
+ int xs, ys;
+ if(!installtex(texnum+i, path(name), xs, ys, true)) conoutf("could not load sky textures");
+ };
+ strcpy_s(lastsky, basename);
+};
+
+COMMAND(loadsky, ARG_1STR);
+
+float cursordepth = 0.9f;
+GLint viewport[4];
+GLdouble mm[16], pm[16];
+vec worldpos;
+
+void readmatrices()
+{
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ glGetDoublev(GL_MODELVIEW_MATRIX, mm);
+ glGetDoublev(GL_PROJECTION_MATRIX, pm);
+};
+
+// stupid function to cater for stupid ATI linux drivers that return incorrect depth values
+
+float depthcorrect(float d)
+{
+ return (d<=1/256.0f) ? d*256 : d;
+};
+
+// find out the 3d target of the crosshair in the world easily and very acurately.
+// sadly many very old cards and drivers appear to fuck up on glReadPixels() and give false
+// coordinates, making shooting and such impossible.
+// also hits map entities which is unwanted.
+// could be replaced by a more acurate version of monster.cpp los() if needed
+
+void readdepth(int w, int h)
+{
+ glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cursordepth);
+ double worldx = 0, worldy = 0, worldz = 0;
+ gluUnProject(w/2, h/2, depthcorrect(cursordepth), mm, pm, viewport, &worldx, &worldz, &worldy);
+ worldpos.x = (float)worldx;
+ worldpos.y = (float)worldy;
+ worldpos.z = (float)worldz;
+ vec r = { (float)mm[0], (float)mm[4], (float)mm[8] };
+ vec u = { (float)mm[1], (float)mm[5], (float)mm[9] };
+ setorient(r, u);
+};
+
+void drawicon(float tx, float ty, int x, int y)
+{
+ glBindTexture(GL_TEXTURE_2D, 5);
+ glBegin(GL_QUADS);
+ tx /= 192;
+ ty /= 192;
+ float o = 1/3.0f;
+ int s = 120;
+ glTexCoord2f(tx, ty); glVertex2i(x, y);
+ glTexCoord2f(tx+o, ty); glVertex2i(x+s, y);
+ glTexCoord2f(tx+o, ty+o); glVertex2i(x+s, y+s);
+ glTexCoord2f(tx, ty+o); glVertex2i(x, y+s);
+ glEnd();
+ xtraverts += 4;
+};
+
+void invertperspective()
+{
+ // This only generates a valid inverse matrix for matrices generated by gluPerspective()
+ GLdouble inv[16];
+ memset(inv, 0, sizeof(inv));
+
+ inv[0*4+0] = 1.0/pm[0*4+0];
+ inv[1*4+1] = 1.0/pm[1*4+1];
+ inv[2*4+3] = 1.0/pm[3*4+2];
+ inv[3*4+2] = -1.0;
+ inv[3*4+3] = pm[2*4+2]/pm[3*4+2];
+
+ glLoadMatrixd(inv);
+};
+
+VARP(crosshairsize, 0, 15, 50);
+
+int dblend = 0;
+void damageblend(int n) { dblend += n; };
+
+VAR(hidestats, 0, 0, 1);
+VARP(crosshairfx, 0, 1, 1);
+
+void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater)
+{
+ readmatrices();
+ if(editmode)
+ {
+ if(cursordepth==1.0f) worldpos = player1->o;
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ cursorupdate();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ };
+
+ glDisable(GL_DEPTH_TEST);
+ invertperspective();
+ glPushMatrix();
+ glOrtho(0, VIRTW, VIRTH, 0, -1, 1);
+ glEnable(GL_BLEND);
+
+ glDepthMask(GL_FALSE);
+
+ if(dblend || underwater)
+ {
+ glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+ glBegin(GL_QUADS);
+ if(dblend) glColor3d(0.0f, 0.9f, 0.9f);
+ else glColor3d(0.9f, 0.5f, 0.0f);
+ glVertex2i(0, 0);
+ glVertex2i(VIRTW, 0);
+ glVertex2i(VIRTW, VIRTH);
+ glVertex2i(0, VIRTH);
+ glEnd();
+ dblend -= curtime/3;
+ if(dblend<0) dblend = 0;
+ };
+
+ glEnable(GL_TEXTURE_2D);
+
+ char *command = getcurcommand();
+ char *player = playerincrosshair();
+ if(command) draw_textf("> %s_", 20, 1570, 2, command);
+ else if(closeent[0]) draw_text(closeent, 20, 1570, 2);
+ else if(player) draw_text(player, 20, 1570, 2);
+
+ renderscores();
+ if(!rendermenu())
+ {
+ glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, 1);
+ glBegin(GL_QUADS);
+ glColor3ub(255,255,255);
+ if(crosshairfx)
+ {
+ if(player1->gunwait) glColor3ub(128,128,128);
+ else if(player1->health<=25) glColor3ub(255,0,0);
+ else if(player1->health<=50) glColor3ub(255,128,0);
+ };
+ float chsize = (float)crosshairsize;
+ glTexCoord2d(0.0, 0.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 - chsize);
+ glTexCoord2d(1.0, 0.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 - chsize);
+ glTexCoord2d(1.0, 1.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 + chsize);
+ glTexCoord2d(0.0, 1.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 + chsize);
+ glEnd();
+ };
+
+ glPopMatrix();
+
+ glPushMatrix();
+ glOrtho(0, VIRTW*4/3, VIRTH*4/3, 0, -1, 1);
+ renderconsole();
+
+ if(!hidestats)
+ {
+ glPopMatrix();
+ glPushMatrix();
+ glOrtho(0, VIRTW*3/2, VIRTH*3/2, 0, -1, 1);
+ draw_textf("fps %d", 3200, 2390, 2, curfps);
+ draw_textf("wqd %d", 3200, 2460, 2, nquads);
+ draw_textf("wvt %d", 3200, 2530, 2, curvert);
+ draw_textf("evt %d", 3200, 2600, 2, xtraverts);
+ };
+
+ glPopMatrix();
+
+ if(player1->state==CS_ALIVE)
+ {
+ glPushMatrix();
+ glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1);
+ draw_textf("%d", 90, 827, 2, player1->health);
+ if(player1->armour) draw_textf("%d", 390, 827, 2, player1->armour);
+ draw_textf("%d", 690, 827, 2, player1->ammo[player1->gunselect]);
+ glPopMatrix();
+ glPushMatrix();
+ glOrtho(0, VIRTW, VIRTH, 0, -1, 1);
+ glDisable(GL_BLEND);
+ drawicon(128, 128, 20, 1650);
+ if(player1->armour) drawicon((float)(player1->armourtype*64), 0, 620, 1650);
+ int g = player1->gunselect;
+ int r = 64;
+ if(g>2) { g -= 3; r = 128; };
+ drawicon((float)(g*64), (float)r, 1220, 1650);
+ glPopMatrix();
+ };
+
+ glDepthMask(GL_TRUE);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_DEPTH_TEST);
+};
+
DELETED src/rendergl.cpp
Index: src/rendergl.cpp
==================================================================
--- src/rendergl.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-// rendergl.cpp: core opengl rendering stuff
-
-#include "cube.h"
-
-#ifdef DARWIN
-#define GL_COMBINE_EXT GL_COMBINE_ARB
-#define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB
-#define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB
-#define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB
-#define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB
-#endif
-
-extern int curvert;
-
-bool hasoverbright = false;
-
-void purgetextures();
-
-GLUquadricObj *qsphere = NULL;
-int glmaxtexsize = 256;
-
-void gl_init(int w, int h)
-{
- //#define fogvalues 0.5f, 0.6f, 0.7f, 1.0f
-
- glViewport(0, 0, w, h);
- glClearDepth(1.0);
- glDepthFunc(GL_LESS);
- glEnable(GL_DEPTH_TEST);
- glShadeModel(GL_SMOOTH);
-
-
- glEnable(GL_FOG);
- glFogi(GL_FOG_MODE, GL_LINEAR);
- glFogf(GL_FOG_DENSITY, 0.25);
- glHint(GL_FOG_HINT, GL_NICEST);
-
-
- glEnable(GL_LINE_SMOOTH);
- glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
- glEnable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(-3.0, -3.0);
-
- glCullFace(GL_FRONT);
- glEnable(GL_CULL_FACE);
-
- char *exts = (char *)glGetString(GL_EXTENSIONS);
-
- if(strstr(exts, "GL_EXT_texture_env_combine")) hasoverbright = true;
- else conoutf("WARNING: cannot use overbright lighting, using old lighting model!");
-
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glmaxtexsize);
-
- purgetextures();
-
- if(!(qsphere = gluNewQuadric())) fatal("glu sphere");
- gluQuadricDrawStyle(qsphere, GLU_FILL);
- gluQuadricOrientation(qsphere, GLU_INSIDE);
- gluQuadricTexture(qsphere, GL_TRUE);
- glNewList(1, GL_COMPILE);
- gluSphere(qsphere, 1, 12, 6);
- glEndList();
-};
-
-void cleangl()
-{
- if(qsphere) gluDeleteQuadric(qsphere);
-};
-
-bool installtex(int tnum, char *texname, int &xs, int &ys, bool clamp)
-{
- SDL_Surface *s = IMG_Load(texname);
- if(!s) { conoutf("couldn't load texture %s", texname); return false; };
- if(s->format->BitsPerPixel!=24) { conoutf("texture must be 24bpp: %s", texname); return false; };
- // loopi(s->w*s->h*3) { uchar *p = (uchar *)s->pixels+i; *p = 255-*p; };
- glBindTexture(GL_TEXTURE_2D, tnum);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //NEAREST);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- xs = s->w;
- ys = s->h;
- while(xs>glmaxtexsize || ys>glmaxtexsize) { xs /= 2; ys /= 2; };
- void *scaledimg = s->pixels;
- if(xs!=s->w)
- {
- conoutf("warning: quality loss: scaling %s", texname); // for voodoo cards under linux
- scaledimg = alloc(xs*ys*3);
- gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE, s->pixels, xs, ys, GL_UNSIGNED_BYTE, scaledimg);
- };
- if(gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, scaledimg)) fatal("could not build mipmaps");
- if(xs!=s->w) free(scaledimg);
- SDL_FreeSurface(s);
- return true;
-};
-
-// management of texture slots
-// each texture slot can have multople texture frames, of which currently only the first is used
-// additional frames can be used for various shaders
-
-const int MAXTEX = 1000;
-int texx[MAXTEX]; // ( loaded texture ) -> ( name, size )
-int texy[MAXTEX];
-string texname[MAXTEX];
-int curtex = 0;
-const int FIRSTTEX = 1000; // opengl id = loaded id + FIRSTTEX
-// std 1+, sky 14+, mdls 20+
-
-const int MAXFRAMES = 2; // increase to allow more complex shader defs
-int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name )
-string mapname[256][MAXFRAMES];
-
-void purgetextures()
-{
- loopi(256) loop(j,MAXFRAMES) mapping[i][j] = 0;
-};
-
-int curtexnum = 0;
-
-void texturereset() { curtexnum = 0; };
-
-void texture(char *aframe, char *name)
-{
- int num = curtexnum++, frame = atoi(aframe);
- if(num<0 || num>=256 || frame<0 || frame>=MAXFRAMES) return;
- mapping[num][frame] = 1;
- char *n = mapname[num][frame];
- strcpy_s(n, name);
- path(n);
-};
-
-COMMAND(texturereset, ARG_NONE);
-COMMAND(texture, ARG_2STR);
-
-int lookuptexture(int tex, int &xs, int &ys)
-{
- int frame = 0; // other frames?
- int tid = mapping[tex][frame];
-
- if(tid>=FIRSTTEX)
- {
- xs = texx[tid-FIRSTTEX];
- ys = texy[tid-FIRSTTEX];
- return tid;
- };
-
- xs = ys = 16;
- if(!tid) return 1; // crosshair :)
-
- loopi(curtex) // lazily happens once per "texture" command, basically
- {
- if(strcmp(mapname[tex][frame], texname[i])==0)
- {
- mapping[tex][frame] = tid = i+FIRSTTEX;
- xs = texx[i];
- ys = texy[i];
- return tid;
- };
- };
-
- if(curtex==MAXTEX) fatal("loaded too many textures");
-
- int tnum = curtex+FIRSTTEX;
- strcpy_s(texname[curtex], mapname[tex][frame]);
-
- sprintf_sd(name)("packages%c%s", PATHDIV, texname[curtex]);
-
- if(installtex(tnum, name, xs, ys))
- {
- mapping[tex][frame] = tnum;
- texx[curtex] = xs;
- texy[curtex] = ys;
- curtex++;
- return tnum;
- }
- else
- {
- return mapping[tex][frame] = FIRSTTEX; // temp fix
- };
-};
-
-void setupworld()
-{
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- setarraypointers();
-
- if(hasoverbright)
- {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
- };
-};
-
-int skyoglid;
-
-struct strip { int tex, start, num; };
-vector strips;
-
-void renderstripssky()
-{
- glBindTexture(GL_TEXTURE_2D, skyoglid);
- loopv(strips) if(strips[i].tex==skyoglid) glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num);
-};
-
-void renderstrips()
-{
- int lasttex = -1;
- loopv(strips) if(strips[i].tex!=skyoglid)
- {
- if(strips[i].tex!=lasttex)
- {
- glBindTexture(GL_TEXTURE_2D, strips[i].tex);
- lasttex = strips[i].tex;
- };
- glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num);
- };
-};
-
-void overbright(float amount) { if(hasoverbright) glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, amount ); };
-
-void addstrip(int tex, int start, int n)
-{
- strip &s = strips.add();
- s.tex = tex;
- s.start = start;
- s.num = n;
-};
-
-VARFP(gamma, 30, 100, 300,
-{
- float f = gamma/100.0f;
- if(SDL_SetGamma(f,f,f)==-1)
- {
- conoutf("Could not set gamma (card/driver doesn't support it?)");
- conoutf("sdl: %s", SDL_GetError());
- };
-});
-
-void transplayer()
-{
- glLoadIdentity();
-
- glRotated(player1->roll,0.0,0.0,1.0);
- glRotated(player1->pitch,-1.0,0.0,0.0);
- glRotated(player1->yaw,0.0,1.0,0.0);
-
- glTranslated(-player1->o.x, (player1->state==CS_DEAD ? player1->eyeheight-0.2f : 0)-player1->o.z, -player1->o.y);
-};
-
-VARP(fov, 10, 105, 120);
-
-int xtraverts;
-
-VAR(fog, 64, 180, 1024);
-VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF);
-
-VARP(hudgun,0,1,1);
-
-char *hudgunnames[] = { "hudguns/fist", "hudguns/shotg", "hudguns/chaing", "hudguns/rocket", "hudguns/rifle" };
-
-void drawhudmodel(int start, int end, float speed, int base)
-{
- rendermodel(hudgunnames[player1->gunselect], start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base);
-};
-
-void drawhudgun(float fovy, float aspect, int farplane)
-{
- if(!hudgun /*|| !player1->gunselect*/) return;
-
- glEnable(GL_CULL_FACE);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(fovy, aspect, 0.3f, farplane);
- glMatrixMode(GL_MODELVIEW);
-
- //glClear(GL_DEPTH_BUFFER_BIT);
- int rtime = reloadtime(player1->gunselect);
- if(player1->lastaction && player1->lastattackgun==player1->gunselect && lastmillis-player1->lastactionlastaction);
- }
- else
- {
- drawhudmodel(6, 1, 100, 0);
- };
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(fovy, aspect, 0.15f, farplane);
- glMatrixMode(GL_MODELVIEW);
-
- glDisable(GL_CULL_FACE);
-};
-
-void gl_drawframe(int w, int h, float curfps)
-{
- float hf = hdr.waterlevel-0.3f;
- float fovy = (float)fov*h/w;
- float aspect = w/(float)h;
- bool underwater = player1->o.z>16)/256.0f, ((fogcolour>>8)&255)/256.0f, (fogcolour&255)/256.0f, 1.0f };
- glFogfv(GL_FOG_COLOR, fogc);
- glClearColor(fogc[0], fogc[1], fogc[2], 1.0f);
-
- if(underwater)
- {
- fovy += (float)sin(lastmillis/1000.0)*2.0f;
- aspect += (float)sin(lastmillis/1000.0+PI)*0.1f;
- glFogi(GL_FOG_START, 0);
- glFogi(GL_FOG_END, (fog+96)/8);
- };
-
- glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- int farplane = fog*5/2;
- gluPerspective(fovy, aspect, 0.15f, farplane);
- glMatrixMode(GL_MODELVIEW);
-
- transplayer();
-
- glEnable(GL_TEXTURE_2D);
-
- int xs, ys;
- skyoglid = lookuptexture(DEFAULT_SKY, xs, ys);
-
- resetcubes();
-
- curvert = 0;
- strips.setsize(0);
-
- render_world(player1->o.x, player1->o.y, player1->o.z,
- (int)player1->yaw, (int)player1->pitch, (float)fov, w, h);
- finishstrips();
-
- setupworld();
-
- renderstripssky();
-
- glLoadIdentity();
- glRotated(player1->pitch, -1.0, 0.0, 0.0);
- glRotated(player1->yaw, 0.0, 1.0, 0.0);
- glRotated(90.0, 1.0, 0.0, 0.0);
- glColor3f(1.0f, 1.0f, 1.0f);
- glDisable(GL_FOG);
- glDepthFunc(GL_GREATER);
- draw_envbox(14, fog*4/3);
- glDepthFunc(GL_LESS);
- glEnable(GL_FOG);
-
- transplayer();
-
- overbright(2);
-
- renderstrips();
-
- xtraverts = 0;
-
- renderclients();
- monsterrender();
-
- renderentities();
-
- renderspheres(curtime);
- renderents();
-
- glDisable(GL_CULL_FACE);
-
- drawhudgun(fovy, aspect, farplane);
-
- overbright(1);
- int nquads = renderwater(hf);
-
- overbright(2);
- render_particles(curtime);
- overbright(1);
-
- glDisable(GL_FOG);
-
- glDisable(GL_TEXTURE_2D);
-
- gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater);
-
- glEnable(GL_CULL_FACE);
- glEnable(GL_FOG);
-};
-
ADDED src/rendergl.cxx
Index: src/rendergl.cxx
==================================================================
--- /dev/null
+++ src/rendergl.cxx
@@ -0,0 +1,398 @@
+// rendergl.cpp: core opengl rendering stuff
+
+#include "cube.h"
+
+#ifdef DARWIN
+#define GL_COMBINE_EXT GL_COMBINE_ARB
+#define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB
+#define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB
+#define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB
+#define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB
+#endif
+
+extern int curvert;
+
+bool hasoverbright = false;
+
+void purgetextures();
+
+GLUquadricObj *qsphere = NULL;
+int glmaxtexsize = 256;
+
+void gl_init(int w, int h)
+{
+ //#define fogvalues 0.5f, 0.6f, 0.7f, 1.0f
+
+ glViewport(0, 0, w, h);
+ glClearDepth(1.0);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_DEPTH_TEST);
+ glShadeModel(GL_SMOOTH);
+
+
+ glEnable(GL_FOG);
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ glFogf(GL_FOG_DENSITY, 0.25);
+ glHint(GL_FOG_HINT, GL_NICEST);
+
+
+ glEnable(GL_LINE_SMOOTH);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ glEnable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(-3.0, -3.0);
+
+ glCullFace(GL_FRONT);
+ glEnable(GL_CULL_FACE);
+
+ char *exts = (char *)glGetString(GL_EXTENSIONS);
+
+ if(strstr(exts, "GL_EXT_texture_env_combine")) hasoverbright = true;
+ else conoutf("WARNING: cannot use overbright lighting, using old lighting model!");
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glmaxtexsize);
+
+ purgetextures();
+
+ if(!(qsphere = gluNewQuadric())) fatal("glu sphere");
+ gluQuadricDrawStyle(qsphere, GLU_FILL);
+ gluQuadricOrientation(qsphere, GLU_INSIDE);
+ gluQuadricTexture(qsphere, GL_TRUE);
+ glNewList(1, GL_COMPILE);
+ gluSphere(qsphere, 1, 12, 6);
+ glEndList();
+};
+
+void cleangl()
+{
+ if(qsphere) gluDeleteQuadric(qsphere);
+};
+
+bool installtex(int tnum, char *texname, int &xs, int &ys, bool clamp)
+{
+ SDL_Surface *s = IMG_Load(texname);
+ if(!s) { conoutf("couldn't load texture %s", texname); return false; };
+ if(s->format->BitsPerPixel!=24) { conoutf("texture must be 24bpp: %s", texname); return false; };
+ // loopi(s->w*s->h*3) { uchar *p = (uchar *)s->pixels+i; *p = 255-*p; };
+ glBindTexture(GL_TEXTURE_2D, tnum);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //NEAREST);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ xs = s->w;
+ ys = s->h;
+ while(xs>glmaxtexsize || ys>glmaxtexsize) { xs /= 2; ys /= 2; };
+ void *scaledimg = s->pixels;
+ if(xs!=s->w)
+ {
+ conoutf("warning: quality loss: scaling %s", texname); // for voodoo cards under linux
+ scaledimg = alloc(xs*ys*3);
+ gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE, s->pixels, xs, ys, GL_UNSIGNED_BYTE, scaledimg);
+ };
+ if(gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, scaledimg)) fatal("could not build mipmaps");
+ if(xs!=s->w) free(scaledimg);
+ SDL_FreeSurface(s);
+ return true;
+};
+
+// management of texture slots
+// each texture slot can have multople texture frames, of which currently only the first is used
+// additional frames can be used for various shaders
+
+const int MAXTEX = 1000;
+int texx[MAXTEX]; // ( loaded texture ) -> ( name, size )
+int texy[MAXTEX];
+string texname[MAXTEX];
+int curtex = 0;
+const int FIRSTTEX = 1000; // opengl id = loaded id + FIRSTTEX
+// std 1+, sky 14+, mdls 20+
+
+const int MAXFRAMES = 2; // increase to allow more complex shader defs
+int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name )
+string mapname[256][MAXFRAMES];
+
+void purgetextures()
+{
+ loopi(256) loop(j,MAXFRAMES) mapping[i][j] = 0;
+};
+
+int curtexnum = 0;
+
+void texturereset() { curtexnum = 0; };
+
+void texture(char *aframe, char *name)
+{
+ int num = curtexnum++, frame = atoi(aframe);
+ if(num<0 || num>=256 || frame<0 || frame>=MAXFRAMES) return;
+ mapping[num][frame] = 1;
+ char *n = mapname[num][frame];
+ strcpy_s(n, name);
+ path(n);
+};
+
+COMMAND(texturereset, ARG_NONE);
+COMMAND(texture, ARG_2STR);
+
+int lookuptexture(int tex, int &xs, int &ys)
+{
+ int frame = 0; // other frames?
+ int tid = mapping[tex][frame];
+
+ if(tid>=FIRSTTEX)
+ {
+ xs = texx[tid-FIRSTTEX];
+ ys = texy[tid-FIRSTTEX];
+ return tid;
+ };
+
+ xs = ys = 16;
+ if(!tid) return 1; // crosshair :)
+
+ loopi(curtex) // lazily happens once per "texture" command, basically
+ {
+ if(strcmp(mapname[tex][frame], texname[i])==0)
+ {
+ mapping[tex][frame] = tid = i+FIRSTTEX;
+ xs = texx[i];
+ ys = texy[i];
+ return tid;
+ };
+ };
+
+ if(curtex==MAXTEX) fatal("loaded too many textures");
+
+ int tnum = curtex+FIRSTTEX;
+ strcpy_s(texname[curtex], mapname[tex][frame]);
+
+ sprintf_sd(name)("packages%c%s", PATHDIV, texname[curtex]);
+
+ if(installtex(tnum, name, xs, ys))
+ {
+ mapping[tex][frame] = tnum;
+ texx[curtex] = xs;
+ texy[curtex] = ys;
+ curtex++;
+ return tnum;
+ }
+ else
+ {
+ return mapping[tex][frame] = FIRSTTEX; // temp fix
+ };
+};
+
+void setupworld()
+{
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ setarraypointers();
+
+ if(hasoverbright)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
+ };
+};
+
+int skyoglid;
+
+struct strip { int tex, start, num; };
+vector strips;
+
+void renderstripssky()
+{
+ glBindTexture(GL_TEXTURE_2D, skyoglid);
+ loopv(strips) if(strips[i].tex==skyoglid) glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num);
+};
+
+void renderstrips()
+{
+ int lasttex = -1;
+ loopv(strips) if(strips[i].tex!=skyoglid)
+ {
+ if(strips[i].tex!=lasttex)
+ {
+ glBindTexture(GL_TEXTURE_2D, strips[i].tex);
+ lasttex = strips[i].tex;
+ };
+ glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num);
+ };
+};
+
+void overbright(float amount) { if(hasoverbright) glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, amount ); };
+
+void addstrip(int tex, int start, int n)
+{
+ strip &s = strips.add();
+ s.tex = tex;
+ s.start = start;
+ s.num = n;
+};
+
+VARFP(gamma, 30, 100, 300,
+{
+ float f = gamma/100.0f;
+ if(SDL_SetGamma(f,f,f)==-1)
+ {
+ conoutf("Could not set gamma (card/driver doesn't support it?)");
+ conoutf("sdl: %s", SDL_GetError());
+ };
+});
+
+void transplayer()
+{
+ glLoadIdentity();
+
+ glRotated(player1->roll,0.0,0.0,1.0);
+ glRotated(player1->pitch,-1.0,0.0,0.0);
+ glRotated(player1->yaw,0.0,1.0,0.0);
+
+ glTranslated(-player1->o.x, (player1->state==CS_DEAD ? player1->eyeheight-0.2f : 0)-player1->o.z, -player1->o.y);
+};
+
+VARP(fov, 10, 105, 120);
+
+int xtraverts;
+
+VAR(fog, 64, 180, 1024);
+VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF);
+
+VARP(hudgun,0,1,1);
+
+char *hudgunnames[] = { "hudguns/fist", "hudguns/shotg", "hudguns/chaing", "hudguns/rocket", "hudguns/rifle" };
+
+void drawhudmodel(int start, int end, float speed, int base)
+{
+ rendermodel(hudgunnames[player1->gunselect], start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base);
+};
+
+void drawhudgun(float fovy, float aspect, int farplane)
+{
+ if(!hudgun /*|| !player1->gunselect*/) return;
+
+ glEnable(GL_CULL_FACE);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(fovy, aspect, 0.3f, farplane);
+ glMatrixMode(GL_MODELVIEW);
+
+ //glClear(GL_DEPTH_BUFFER_BIT);
+ int rtime = reloadtime(player1->gunselect);
+ if(player1->lastaction && player1->lastattackgun==player1->gunselect && lastmillis-player1->lastactionlastaction);
+ }
+ else
+ {
+ drawhudmodel(6, 1, 100, 0);
+ };
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(fovy, aspect, 0.15f, farplane);
+ glMatrixMode(GL_MODELVIEW);
+
+ glDisable(GL_CULL_FACE);
+};
+
+void gl_drawframe(int w, int h, float curfps)
+{
+ float hf = hdr.waterlevel-0.3f;
+ float fovy = (float)fov*h/w;
+ float aspect = w/(float)h;
+ bool underwater = player1->o.z>16)/256.0f, ((fogcolour>>8)&255)/256.0f, (fogcolour&255)/256.0f, 1.0f };
+ glFogfv(GL_FOG_COLOR, fogc);
+ glClearColor(fogc[0], fogc[1], fogc[2], 1.0f);
+
+ if(underwater)
+ {
+ fovy += (float)sin(lastmillis/1000.0)*2.0f;
+ aspect += (float)sin(lastmillis/1000.0+PI)*0.1f;
+ glFogi(GL_FOG_START, 0);
+ glFogi(GL_FOG_END, (fog+96)/8);
+ };
+
+ glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ int farplane = fog*5/2;
+ gluPerspective(fovy, aspect, 0.15f, farplane);
+ glMatrixMode(GL_MODELVIEW);
+
+ transplayer();
+
+ glEnable(GL_TEXTURE_2D);
+
+ int xs, ys;
+ skyoglid = lookuptexture(DEFAULT_SKY, xs, ys);
+
+ resetcubes();
+
+ curvert = 0;
+ strips.setsize(0);
+
+ render_world(player1->o.x, player1->o.y, player1->o.z,
+ (int)player1->yaw, (int)player1->pitch, (float)fov, w, h);
+ finishstrips();
+
+ setupworld();
+
+ renderstripssky();
+
+ glLoadIdentity();
+ glRotated(player1->pitch, -1.0, 0.0, 0.0);
+ glRotated(player1->yaw, 0.0, 1.0, 0.0);
+ glRotated(90.0, 1.0, 0.0, 0.0);
+ glColor3f(1.0f, 1.0f, 1.0f);
+ glDisable(GL_FOG);
+ glDepthFunc(GL_GREATER);
+ draw_envbox(14, fog*4/3);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_FOG);
+
+ transplayer();
+
+ overbright(2);
+
+ renderstrips();
+
+ xtraverts = 0;
+
+ renderclients();
+ monsterrender();
+
+ renderentities();
+
+ renderspheres(curtime);
+ renderents();
+
+ glDisable(GL_CULL_FACE);
+
+ drawhudgun(fovy, aspect, farplane);
+
+ overbright(1);
+ int nquads = renderwater(hf);
+
+ overbright(2);
+ render_particles(curtime);
+ overbright(1);
+
+ glDisable(GL_FOG);
+
+ glDisable(GL_TEXTURE_2D);
+
+ gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater);
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_FOG);
+};
+
DELETED src/rendermd2.cpp
Index: src/rendermd2.cpp
==================================================================
--- src/rendermd2.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-// rendermd2.cpp: loader code adapted from a nehe tutorial
-
-#include "cube.h"
-
-struct md2_header
-{
- int magic;
- int version;
- int skinWidth, skinHeight;
- int frameSize;
- int numSkins, numVertices, numTexcoords;
- int numTriangles, numGlCommands, numFrames;
- int offsetSkins, offsetTexcoords, offsetTriangles;
- int offsetFrames, offsetGlCommands, offsetEnd;
-};
-
-struct md2_vertex
-{
- uchar vertex[3], lightNormalIndex;
-};
-
-struct md2_frame
-{
- float scale[3];
- float translate[3];
- char name[16];
- md2_vertex vertices[1];
-};
-
-struct md2
-{
- int numGlCommands;
- int* glCommands;
- int numTriangles;
- int frameSize;
- int numFrames;
- int numVerts;
- char* frames;
- vec **mverts;
- int displaylist;
- int displaylistverts;
-
- mapmodelinfo mmi;
- char *loadname;
- int mdlnum;
- bool loaded;
-
- bool load(char* filename);
- void render(vec &light, int numFrame, int range, float x, float y, float z, float yaw, float pitch, float scale, float speed, int snap, int basetime);
- void scale(int frame, float scale, int sn);
-
- md2() : numGlCommands(0), frameSize(0), numFrames(0), displaylist(0), loaded(false) {};
-
- ~md2()
- {
- if(glCommands)
- delete [] glCommands;
- if(frames)
- delete [] frames;
- }
-};
-
-
-bool md2::load(char* filename)
-{
- FILE* file;
- md2_header header;
-
- if((file= fopen(filename, "rb"))==NULL) return false;
-
- fread(&header, sizeof(md2_header), 1, file);
- endianswap(&header, sizeof(int), sizeof(md2_header)/sizeof(int));
-
- if(header.magic!= 844121161 || header.version!=8) return false;
-
- frames = new char[header.frameSize*header.numFrames];
- if(frames==NULL) return false;
-
- fseek(file, header.offsetFrames, SEEK_SET);
- fread(frames, header.frameSize*header.numFrames, 1, file);
-
- for(int i = 0; i < header.numFrames; ++i)
- {
- endianswap(frames + i * header.frameSize, sizeof(float), 6);
- }
-
- glCommands = new int[header.numGlCommands];
- if(glCommands==NULL) return false;
-
- fseek(file, header.offsetGlCommands, SEEK_SET);
- fread(glCommands, header.numGlCommands*sizeof(int), 1, file);
-
- endianswap(glCommands, sizeof(int), header.numGlCommands);
-
- numFrames = header.numFrames;
- numGlCommands= header.numGlCommands;
- frameSize = header.frameSize;
- numTriangles = header.numTriangles;
- numVerts = header.numVertices;
-
- fclose(file);
-
- mverts = new vec*[numFrames];
- loopj(numFrames) mverts[j] = NULL;
-
- return true;
-};
-
-float snap(int sn, float f) { return sn ? (float)(((int)(f+sn*0.5f))&(~(sn-1))) : f; };
-
-void md2::scale(int frame, float scale, int sn)
-{
- mverts[frame] = new vec[numVerts];
- md2_frame *cf = (md2_frame *) ((char*)frames+frameSize*frame);
- float sc = 16.0f/scale;
- loop(vi, numVerts)
- {
- uchar *cv = (uchar *)&cf->vertices[vi].vertex;
- vec *v = &(mverts[frame])[vi];
- v->x = (snap(sn, cv[0]*cf->scale[0])+cf->translate[0])/sc;
- v->y = -(snap(sn, cv[1]*cf->scale[1])+cf->translate[1])/sc;
- v->z = (snap(sn, cv[2]*cf->scale[2])+cf->translate[2])/sc;
- };
-};
-
-void md2::render(vec &light, int frame, int range, float x, float y, float z, float yaw, float pitch, float sc, float speed, int snap, int basetime)
-{
- loopi(range) if(!mverts[frame+i]) scale(frame+i, sc, snap);
-
- glPushMatrix ();
- glTranslatef(x, y, z);
- glRotatef(yaw+180, 0, -1, 0);
- glRotatef(pitch, 0, 0, 1);
-
- glColor3fv((float *)&light);
-
- if(displaylist && frame==0 && range==1)
- {
- glCallList(displaylist);
- xtraverts += displaylistverts;
- }
- else
- {
- if(frame==0 && range==1)
- {
- static int displaylistn = 10;
- glNewList(displaylist = displaylistn++, GL_COMPILE);
- displaylistverts = xtraverts;
- };
-
- int time = lastmillis-basetime;
- int fr1 = (int)(time/speed);
- float frac1 = (time-fr1*speed)/speed;
- float frac2 = 1-frac1;
- fr1 = fr1%range+frame;
- int fr2 = fr1+1;
- if(fr2>=frame+range) fr2 = frame;
- vec *verts1 = mverts[fr1];
- vec *verts2 = mverts[fr2];
-
- for(int *command = glCommands; (*command)!=0;)
- {
- int numVertex = *command++;
- if(numVertex>0) { glBegin(GL_TRIANGLE_STRIP); }
- else { glBegin(GL_TRIANGLE_FAN); numVertex = -numVertex; };
-
- loopi(numVertex)
- {
- float tu = *((float*)command++);
- float tv = *((float*)command++);
- glTexCoord2f(tu, tv);
- int vn = *command++;
- vec &v1 = verts1[vn];
- vec &v2 = verts2[vn];
- #define ip(c) v1.c*frac2+v2.c*frac1
- glVertex3f(ip(x), ip(z), ip(y));
- };
-
- xtraverts += numVertex;
-
- glEnd();
- };
-
- if(displaylist)
- {
- glEndList();
- displaylistverts = xtraverts-displaylistverts;
- };
- };
-
- glPopMatrix();
-}
-
-hashtable *mdllookup = NULL;
-vector mapmodels;
-const int FIRSTMDL = 20;
-
-void delayedload(md2 *m)
-{
- if(!m->loaded)
- {
- sprintf_sd(name1)("packages/models/%s/tris.md2", m->loadname);
- if(!m->load(path(name1))) fatal("loadmodel: ", name1);
- sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname);
- int xs, ys;
- installtex(FIRSTMDL+m->mdlnum, path(name2), xs, ys);
- m->loaded = true;
- };
-};
-
-int modelnum = 0;
-
-md2 *loadmodel(char *name)
-{
- if(!mdllookup) mdllookup = new hashtable;
- md2 **mm = mdllookup->access(name);
- if(mm) return *mm;
- md2 *m = new md2();
- m->mdlnum = modelnum++;
- mapmodelinfo mmi = { 2, 2, 0, 0, "" };
- m->mmi = mmi;
- m->loadname = newstring(name);
- mdllookup->access(m->loadname, &m);
- return m;
-};
-
-void mapmodel(char *rad, char *h, char *zoff, char *snap, char *name)
-{
- md2 *m = loadmodel(name);
- mapmodelinfo mmi = { atoi(rad), atoi(h), atoi(zoff), atoi(snap), m->loadname };
- m->mmi = mmi;
- mapmodels.add(m);
-};
-
-void mapmodelreset() { mapmodels.setsize(0); };
-
-mapmodelinfo &getmminfo(int i) { return immi : *(mapmodelinfo *)0; };
-
-COMMAND(mapmodel, ARG_5STR);
-COMMAND(mapmodelreset, ARG_NONE);
-
-void rendermodel(char *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap, int basetime)
-{
- md2 *m = loadmodel(mdl);
-
- if(isoccluded(player1->o.x, player1->o.y, x-rad, z-rad, rad*2)) return;
-
- delayedload(m);
-
- int xs, ys;
- glBindTexture(GL_TEXTURE_2D, tex ? lookuptexture(tex, xs, ys) : FIRSTMDL+m->mdlnum);
-
- int ix = (int)x;
- int iy = (int)z;
- vec light = { 1.0f, 1.0f, 1.0f };
-
- if(!OUTBORD(ix, iy))
- {
- sqr *s = S(ix,iy);
- float ll = 256.0f; // 0.96f;
- float of = 0.0f; // 0.1f;
- light.x = s->r/ll+of;
- light.y = s->g/ll+of;
- light.z = s->b/ll+of;
- };
-
- if(teammate)
- {
- light.x *= 0.6f;
- light.y *= 0.7f;
- light.z *= 1.2f;
- };
-
- m->render(light, frame, range, x, y, z, yaw, pitch, scale, speed, snap, basetime);
-};
ADDED src/rendermd2.cxx
Index: src/rendermd2.cxx
==================================================================
--- /dev/null
+++ src/rendermd2.cxx
@@ -0,0 +1,275 @@
+// rendermd2.cpp: loader code adapted from a nehe tutorial
+
+#include "cube.h"
+
+struct md2_header
+{
+ int magic;
+ int version;
+ int skinWidth, skinHeight;
+ int frameSize;
+ int numSkins, numVertices, numTexcoords;
+ int numTriangles, numGlCommands, numFrames;
+ int offsetSkins, offsetTexcoords, offsetTriangles;
+ int offsetFrames, offsetGlCommands, offsetEnd;
+};
+
+struct md2_vertex
+{
+ uchar vertex[3], lightNormalIndex;
+};
+
+struct md2_frame
+{
+ float scale[3];
+ float translate[3];
+ char name[16];
+ md2_vertex vertices[1];
+};
+
+struct md2
+{
+ int numGlCommands;
+ int* glCommands;
+ int numTriangles;
+ int frameSize;
+ int numFrames;
+ int numVerts;
+ char* frames;
+ vec **mverts;
+ int displaylist;
+ int displaylistverts;
+
+ mapmodelinfo mmi;
+ char *loadname;
+ int mdlnum;
+ bool loaded;
+
+ bool load(char* filename);
+ void render(vec &light, int numFrame, int range, float x, float y, float z, float yaw, float pitch, float scale, float speed, int snap, int basetime);
+ void scale(int frame, float scale, int sn);
+
+ md2() : numGlCommands(0), frameSize(0), numFrames(0), displaylist(0), loaded(false) {};
+
+ ~md2()
+ {
+ if(glCommands)
+ delete [] glCommands;
+ if(frames)
+ delete [] frames;
+ }
+};
+
+
+bool md2::load(char* filename)
+{
+ FILE* file;
+ md2_header header;
+
+ if((file= fopen(filename, "rb"))==NULL) return false;
+
+ fread(&header, sizeof(md2_header), 1, file);
+ endianswap(&header, sizeof(int), sizeof(md2_header)/sizeof(int));
+
+ if(header.magic!= 844121161 || header.version!=8) return false;
+
+ frames = new char[header.frameSize*header.numFrames];
+ if(frames==NULL) return false;
+
+ fseek(file, header.offsetFrames, SEEK_SET);
+ fread(frames, header.frameSize*header.numFrames, 1, file);
+
+ for(int i = 0; i < header.numFrames; ++i)
+ {
+ endianswap(frames + i * header.frameSize, sizeof(float), 6);
+ }
+
+ glCommands = new int[header.numGlCommands];
+ if(glCommands==NULL) return false;
+
+ fseek(file, header.offsetGlCommands, SEEK_SET);
+ fread(glCommands, header.numGlCommands*sizeof(int), 1, file);
+
+ endianswap(glCommands, sizeof(int), header.numGlCommands);
+
+ numFrames = header.numFrames;
+ numGlCommands= header.numGlCommands;
+ frameSize = header.frameSize;
+ numTriangles = header.numTriangles;
+ numVerts = header.numVertices;
+
+ fclose(file);
+
+ mverts = new vec*[numFrames];
+ loopj(numFrames) mverts[j] = NULL;
+
+ return true;
+};
+
+float snap(int sn, float f) { return sn ? (float)(((int)(f+sn*0.5f))&(~(sn-1))) : f; };
+
+void md2::scale(int frame, float scale, int sn)
+{
+ mverts[frame] = new vec[numVerts];
+ md2_frame *cf = (md2_frame *) ((char*)frames+frameSize*frame);
+ float sc = 16.0f/scale;
+ loop(vi, numVerts)
+ {
+ uchar *cv = (uchar *)&cf->vertices[vi].vertex;
+ vec *v = &(mverts[frame])[vi];
+ v->x = (snap(sn, cv[0]*cf->scale[0])+cf->translate[0])/sc;
+ v->y = -(snap(sn, cv[1]*cf->scale[1])+cf->translate[1])/sc;
+ v->z = (snap(sn, cv[2]*cf->scale[2])+cf->translate[2])/sc;
+ };
+};
+
+void md2::render(vec &light, int frame, int range, float x, float y, float z, float yaw, float pitch, float sc, float speed, int snap, int basetime)
+{
+ loopi(range) if(!mverts[frame+i]) scale(frame+i, sc, snap);
+
+ glPushMatrix ();
+ glTranslatef(x, y, z);
+ glRotatef(yaw+180, 0, -1, 0);
+ glRotatef(pitch, 0, 0, 1);
+
+ glColor3fv((float *)&light);
+
+ if(displaylist && frame==0 && range==1)
+ {
+ glCallList(displaylist);
+ xtraverts += displaylistverts;
+ }
+ else
+ {
+ if(frame==0 && range==1)
+ {
+ static int displaylistn = 10;
+ glNewList(displaylist = displaylistn++, GL_COMPILE);
+ displaylistverts = xtraverts;
+ };
+
+ int time = lastmillis-basetime;
+ int fr1 = (int)(time/speed);
+ float frac1 = (time-fr1*speed)/speed;
+ float frac2 = 1-frac1;
+ fr1 = fr1%range+frame;
+ int fr2 = fr1+1;
+ if(fr2>=frame+range) fr2 = frame;
+ vec *verts1 = mverts[fr1];
+ vec *verts2 = mverts[fr2];
+
+ for(int *command = glCommands; (*command)!=0;)
+ {
+ int numVertex = *command++;
+ if(numVertex>0) { glBegin(GL_TRIANGLE_STRIP); }
+ else { glBegin(GL_TRIANGLE_FAN); numVertex = -numVertex; };
+
+ loopi(numVertex)
+ {
+ float tu = *((float*)command++);
+ float tv = *((float*)command++);
+ glTexCoord2f(tu, tv);
+ int vn = *command++;
+ vec &v1 = verts1[vn];
+ vec &v2 = verts2[vn];
+ #define ip(c) v1.c*frac2+v2.c*frac1
+ glVertex3f(ip(x), ip(z), ip(y));
+ };
+
+ xtraverts += numVertex;
+
+ glEnd();
+ };
+
+ if(displaylist)
+ {
+ glEndList();
+ displaylistverts = xtraverts-displaylistverts;
+ };
+ };
+
+ glPopMatrix();
+}
+
+hashtable *mdllookup = NULL;
+vector mapmodels;
+const int FIRSTMDL = 20;
+
+void delayedload(md2 *m)
+{
+ if(!m->loaded)
+ {
+ sprintf_sd(name1)("packages/models/%s/tris.md2", m->loadname);
+ if(!m->load(path(name1))) fatal("loadmodel: ", name1);
+ sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname);
+ int xs, ys;
+ installtex(FIRSTMDL+m->mdlnum, path(name2), xs, ys);
+ m->loaded = true;
+ };
+};
+
+int modelnum = 0;
+
+md2 *loadmodel(char *name)
+{
+ if(!mdllookup) mdllookup = new hashtable;
+ md2 **mm = mdllookup->access(name);
+ if(mm) return *mm;
+ md2 *m = new md2();
+ m->mdlnum = modelnum++;
+ mapmodelinfo mmi = { 2, 2, 0, 0, "" };
+ m->mmi = mmi;
+ m->loadname = newstring(name);
+ mdllookup->access(m->loadname, &m);
+ return m;
+};
+
+void mapmodel(char *rad, char *h, char *zoff, char *snap, char *name)
+{
+ md2 *m = loadmodel(name);
+ mapmodelinfo mmi = { atoi(rad), atoi(h), atoi(zoff), atoi(snap), m->loadname };
+ m->mmi = mmi;
+ mapmodels.add(m);
+};
+
+void mapmodelreset() { mapmodels.setsize(0); };
+
+mapmodelinfo &getmminfo(int i) { return immi : *(mapmodelinfo *)0; };
+
+COMMAND(mapmodel, ARG_5STR);
+COMMAND(mapmodelreset, ARG_NONE);
+
+void rendermodel(char *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap, int basetime)
+{
+ md2 *m = loadmodel(mdl);
+
+ if(isoccluded(player1->o.x, player1->o.y, x-rad, z-rad, rad*2)) return;
+
+ delayedload(m);
+
+ int xs, ys;
+ glBindTexture(GL_TEXTURE_2D, tex ? lookuptexture(tex, xs, ys) : FIRSTMDL+m->mdlnum);
+
+ int ix = (int)x;
+ int iy = (int)z;
+ vec light = { 1.0f, 1.0f, 1.0f };
+
+ if(!OUTBORD(ix, iy))
+ {
+ sqr *s = S(ix,iy);
+ float ll = 256.0f; // 0.96f;
+ float of = 0.0f; // 0.1f;
+ light.x = s->r/ll+of;
+ light.y = s->g/ll+of;
+ light.z = s->b/ll+of;
+ };
+
+ if(teammate)
+ {
+ light.x *= 0.6f;
+ light.y *= 0.7f;
+ light.z *= 1.2f;
+ };
+
+ m->render(light, frame, range, x, y, z, yaw, pitch, scale, speed, snap, basetime);
+};
DELETED src/renderparticles.cpp
Index: src/renderparticles.cpp
==================================================================
--- src/renderparticles.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// renderparticles.cpp
-
-#include "cube.h"
-
-const int MAXPARTICLES = 10500;
-const int NUMPARTCUTOFF = 20;
-struct particle { vec o, d; int fade, type; int millis; particle *next; };
-particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
-bool parinit = false;
-
-VARP(maxparticles, 100, 2000, MAXPARTICLES-500);
-
-void newparticle(vec &o, vec &d, int fade, int type)
-{
- if(!parinit)
- {
- loopi(MAXPARTICLES)
- {
- particles[i].next = parempty;
- parempty = &particles[i];
- };
- parinit = true;
- };
- if(parempty)
- {
- particle *p = parempty;
- parempty = p->next;
- p->o = o;
- p->d = d;
- p->fade = fade;
- p->type = type;
- p->millis = lastmillis;
- p->next = parlist;
- parlist = p;
- };
-};
-
-VAR(demotracking, 0, 0, 1);
-VARP(particlesize, 20, 100, 500);
-
-vec right, up;
-
-void setorient(vec &r, vec &u) { right = r; up = u; };
-
-void render_particles(int time)
-{
- if(demoplayback && demotracking)
- {
- vec nom = { 0, 0, 0 };
- newparticle(player1->o, nom, 100000000, 8);
- };
-
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
- glDisable(GL_FOG);
-
- struct parttype { float r, g, b; int gr, tex; float sz; } parttypes[] =
- {
- { 0.7f, 0.6f, 0.3f, 2, 3, 0.06f }, // yellow: sparks
- { 0.5f, 0.5f, 0.5f, 20, 7, 0.15f }, // grey: small smoke
- { 0.2f, 0.2f, 1.0f, 20, 3, 0.08f }, // blue: edit mode entities
- { 1.0f, 0.1f, 0.1f, 1, 7, 0.06f }, // red: blood spats
- { 1.0f, 0.8f, 0.8f, 20, 6, 1.2f }, // yellow: fireball1
- { 0.5f, 0.5f, 0.5f, 20, 7, 0.6f }, // grey: big smoke
- { 1.0f, 1.0f, 1.0f, 20, 8, 1.2f }, // blue: fireball2
- { 1.0f, 1.0f, 1.0f, 20, 9, 1.2f }, // green: fireball3
- { 1.0f, 0.1f, 0.1f, 0, 7, 0.2f }, // red: demotrack
- };
-
- int numrender = 0;
-
- for(particle *p, **pp = &parlist; p = *pp;)
- {
- parttype *pt = &parttypes[p->type];
-
- glBindTexture(GL_TEXTURE_2D, pt->tex);
- glBegin(GL_QUADS);
-
- glColor3d(pt->r, pt->g, pt->b);
- float sz = pt->sz*particlesize/100.0f;
- // perf varray?
- glTexCoord2f(0.0, 1.0); glVertex3d(p->o.x+(-right.x+up.x)*sz, p->o.z+(-right.y+up.y)*sz, p->o.y+(-right.z+up.z)*sz);
- glTexCoord2f(1.0, 1.0); glVertex3d(p->o.x+( right.x+up.x)*sz, p->o.z+( right.y+up.y)*sz, p->o.y+( right.z+up.z)*sz);
- glTexCoord2f(1.0, 0.0); glVertex3d(p->o.x+( right.x-up.x)*sz, p->o.z+( right.y-up.y)*sz, p->o.y+( right.z-up.z)*sz);
- glTexCoord2f(0.0, 0.0); glVertex3d(p->o.x+(-right.x-up.x)*sz, p->o.z+(-right.y-up.y)*sz, p->o.y+(-right.z-up.z)*sz);
- glEnd();
- xtraverts += 4;
-
- if(numrender++>maxparticles || (p->fade -= time)<0)
- {
- *pp = p->next;
- p->next = parempty;
- parempty = p;
- }
- else
- {
- if(pt->gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*curtime/(pt->gr*10000);
- vec a = p->d;
- vmul(a,time);
- vdiv(a,20000.0f);
- vadd(p->o, a);
- pp = &p->next;
- };
- };
-
- glEnable(GL_FOG);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
-};
-
-void particle_splash(int type, int num, int fade, vec &p)
-{
- loopi(num)
- {
- const int radius = type==5 ? 50 : 150;
- int x, y, z;
- do
- {
- x = rnd(radius*2)-radius;
- y = rnd(radius*2)-radius;
- z = rnd(radius*2)-radius;
- }
- while(x*x+y*y+z*z>radius*radius);
- vec d = { (float)x, (float)y, (float)z };
- newparticle(p, d, rnd(fade*3), type);
- };
-};
-
-void particle_trail(int type, int fade, vec &s, vec &e)
-{
- vdist(d, v, s, e);
- vdiv(v, d*2+0.1f);
- vec p = s;
- loopi((int)d*2)
- {
- vadd(p, v);
- vec d = { float(rnd(11)-5), float(rnd(11)-5), float(rnd(11)-5) };
- newparticle(p, d, rnd(fade)+fade, type);
- };
-};
-
ADDED src/renderparticles.cxx
Index: src/renderparticles.cxx
==================================================================
--- /dev/null
+++ src/renderparticles.cxx
@@ -0,0 +1,142 @@
+// renderparticles.cpp
+
+#include "cube.h"
+
+const int MAXPARTICLES = 10500;
+const int NUMPARTCUTOFF = 20;
+struct particle { vec o, d; int fade, type; int millis; particle *next; };
+particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
+bool parinit = false;
+
+VARP(maxparticles, 100, 2000, MAXPARTICLES-500);
+
+void newparticle(vec &o, vec &d, int fade, int type)
+{
+ if(!parinit)
+ {
+ loopi(MAXPARTICLES)
+ {
+ particles[i].next = parempty;
+ parempty = &particles[i];
+ };
+ parinit = true;
+ };
+ if(parempty)
+ {
+ particle *p = parempty;
+ parempty = p->next;
+ p->o = o;
+ p->d = d;
+ p->fade = fade;
+ p->type = type;
+ p->millis = lastmillis;
+ p->next = parlist;
+ parlist = p;
+ };
+};
+
+VAR(demotracking, 0, 0, 1);
+VARP(particlesize, 20, 100, 500);
+
+vec right, up;
+
+void setorient(vec &r, vec &u) { right = r; up = u; };
+
+void render_particles(int time)
+{
+ if(demoplayback && demotracking)
+ {
+ vec nom = { 0, 0, 0 };
+ newparticle(player1->o, nom, 100000000, 8);
+ };
+
+ glDepthMask(GL_FALSE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
+ glDisable(GL_FOG);
+
+ struct parttype { float r, g, b; int gr, tex; float sz; } parttypes[] =
+ {
+ { 0.7f, 0.6f, 0.3f, 2, 3, 0.06f }, // yellow: sparks
+ { 0.5f, 0.5f, 0.5f, 20, 7, 0.15f }, // grey: small smoke
+ { 0.2f, 0.2f, 1.0f, 20, 3, 0.08f }, // blue: edit mode entities
+ { 1.0f, 0.1f, 0.1f, 1, 7, 0.06f }, // red: blood spats
+ { 1.0f, 0.8f, 0.8f, 20, 6, 1.2f }, // yellow: fireball1
+ { 0.5f, 0.5f, 0.5f, 20, 7, 0.6f }, // grey: big smoke
+ { 1.0f, 1.0f, 1.0f, 20, 8, 1.2f }, // blue: fireball2
+ { 1.0f, 1.0f, 1.0f, 20, 9, 1.2f }, // green: fireball3
+ { 1.0f, 0.1f, 0.1f, 0, 7, 0.2f }, // red: demotrack
+ };
+
+ int numrender = 0;
+
+ for(particle *p, **pp = &parlist; p = *pp;)
+ {
+ parttype *pt = &parttypes[p->type];
+
+ glBindTexture(GL_TEXTURE_2D, pt->tex);
+ glBegin(GL_QUADS);
+
+ glColor3d(pt->r, pt->g, pt->b);
+ float sz = pt->sz*particlesize/100.0f;
+ // perf varray?
+ glTexCoord2f(0.0, 1.0); glVertex3d(p->o.x+(-right.x+up.x)*sz, p->o.z+(-right.y+up.y)*sz, p->o.y+(-right.z+up.z)*sz);
+ glTexCoord2f(1.0, 1.0); glVertex3d(p->o.x+( right.x+up.x)*sz, p->o.z+( right.y+up.y)*sz, p->o.y+( right.z+up.z)*sz);
+ glTexCoord2f(1.0, 0.0); glVertex3d(p->o.x+( right.x-up.x)*sz, p->o.z+( right.y-up.y)*sz, p->o.y+( right.z-up.z)*sz);
+ glTexCoord2f(0.0, 0.0); glVertex3d(p->o.x+(-right.x-up.x)*sz, p->o.z+(-right.y-up.y)*sz, p->o.y+(-right.z-up.z)*sz);
+ glEnd();
+ xtraverts += 4;
+
+ if(numrender++>maxparticles || (p->fade -= time)<0)
+ {
+ *pp = p->next;
+ p->next = parempty;
+ parempty = p;
+ }
+ else
+ {
+ if(pt->gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*curtime/(pt->gr*10000);
+ vec a = p->d;
+ vmul(a,time);
+ vdiv(a,20000.0f);
+ vadd(p->o, a);
+ pp = &p->next;
+ };
+ };
+
+ glEnable(GL_FOG);
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+};
+
+void particle_splash(int type, int num, int fade, vec &p)
+{
+ loopi(num)
+ {
+ const int radius = type==5 ? 50 : 150;
+ int x, y, z;
+ do
+ {
+ x = rnd(radius*2)-radius;
+ y = rnd(radius*2)-radius;
+ z = rnd(radius*2)-radius;
+ }
+ while(x*x+y*y+z*z>radius*radius);
+ vec d = { (float)x, (float)y, (float)z };
+ newparticle(p, d, rnd(fade*3), type);
+ };
+};
+
+void particle_trail(int type, int fade, vec &s, vec &e)
+{
+ vdist(d, v, s, e);
+ vdiv(v, d*2+0.1f);
+ vec p = s;
+ loopi((int)d*2)
+ {
+ vadd(p, v);
+ vec d = { float(rnd(11)-5), float(rnd(11)-5), float(rnd(11)-5) };
+ newparticle(p, d, rnd(fade)+fade, type);
+ };
+};
+
DELETED src/rendertext.cpp
Index: src/rendertext.cpp
==================================================================
--- src/rendertext.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-// rendertext.cpp: based on Don's gl_text.cpp
-
-#include "cube.h"
-
-short char_coords[96][4] =
-{
- {0,0,25,64}, //!
- {25,0,54,64}, //"
- {54,0,107,64}, //#
- {107,0,148,64}, //$
- {148,0,217,64}, //%
- {217,0,263,64}, //&
- {263,0,280,64}, //'
- {280,0,309,64}, //(
- {309,0,338,64}, //)
- {338,0,379,64}, //*
- {379,0,432,64}, //+
- {432,0,455,64}, //,
- {455,0,484,64}, //-
- {0,64,21,128}, //.
- {23,64,52,128}, ///
- {52,64,93,128}, //0
- {93,64,133,128}, //1
- {133,64,174,128}, //2
- {174,64,215,128}, //3
- {215,64,256,128}, //4
- {256,64,296,128}, //5
- {296,64,337,128}, //6
- {337,64,378,128}, //7
- {378,64,419,128}, //8
- {419,64,459,128}, //9
- {459,64,488,128}, //:
- {0,128,29,192}, //;
- {29,128,81,192}, //<
- {81,128,134,192}, //=
- {134,128,186,192}, //>
- {186,128,221,192}, //?
- {221,128,285,192}, //@
- {285,128,329,192}, //A
- {329,128,373,192}, //B
- {373,128,418,192}, //C
- {418,128,467,192}, //D
- {0,192,40,256}, //E
- {40,192,77,256}, //F
- {77,192,127,256}, //G
- {127,192,175,256}, //H
- {175,192,202,256}, //I
- {202,192,231,256}, //J
- {231,192,275,256}, //K
- {275,192,311,256}, //L
- {311,192,365,256}, //M
- {365,192,413,256}, //N
- {413,192,463,256}, //O
- {1,256,38,320}, //P
- {38,256,89,320}, //Q
- {89,256,133,320}, //R
- {133,256,176,320}, //S
- {177,256,216,320}, //T
- {217,256,263,320}, //U
- {263,256,307,320}, //V
- {307,256,370,320}, //W
- {370,256,414,320}, //X
- {414,256,453,320}, //Y
- {453,256,497,320}, //Z
- {0,320,29,384}, //[
- {29,320,58,384}, //"\"
- {59,320,87,384}, //]
- {87,320,139,384}, //^
- {139,320,180,384}, //_
- {180,320,221,384}, //`
- {221,320,259,384}, //a
- {259,320,299,384}, //b
- {299,320,332,384}, //c
- {332,320,372,384}, //d
- {372,320,411,384}, //e
- {411,320,433,384}, //f
- {435,320,473,384}, //g
- {0,384,40,448}, //h
- {40,384,56,448}, //i
- {58,384,80,448}, //j
- {80,384,118,448}, //k
- {118,384,135,448}, //l
- {135,384,197,448}, //m
- {197,384,238,448}, //n
- {238,384,277,448}, //o
- {277,384,317,448}, //p
- {317,384,356,448}, //q
- {357,384,384,448}, //r
- {385,384,417,448}, //s
- {417,384,442,448}, //t
- {443,384,483,448}, //u
- {0,448,38,512}, //v
- {38,448,90,512}, //w
- {90,448,128,512}, //x
- {128,448,166,512}, //y
- {166,448,200,512}, //z
- {200,448,241,512}, //{
- {241,448,270,512}, //|
- {270,448,310,512}, //}
- {310,448,363,512}, //~
-};
-
-int text_width(char *str)
-{
- int x = 0;
- for (int i = 0; str[i] != 0; i++)
- {
- int c = str[i];
- if(c=='\t') { x = (x+PIXELTAB)/PIXELTAB*PIXELTAB; continue; };
- if(c=='\f') continue;
- if(c==' ') { x += FONTH/2; continue; };
- c -= 33;
- if(c<0 || c>=95) continue;
- int in_width = char_coords[c][2] - char_coords[c][0];
- x += in_width + 1;
- }
- return x;
-}
-
-
-void draw_textf(char *fstr, int left, int top, int gl_num, ...)
-{
- sprintf_sdlv(str, gl_num, fstr);
- draw_text(str, left, top, gl_num);
-};
-
-void draw_text(char *str, int left, int top, int gl_num)
-{
- glBlendFunc(GL_ONE, GL_ONE);
- glBindTexture(GL_TEXTURE_2D, gl_num);
- glColor3ub(255,255,255);
-
- int x = left;
- int y = top;
-
- int i;
- float in_left, in_top, in_right, in_bottom;
- int in_width, in_height;
-
- for (i = 0; str[i] != 0; i++)
- {
- int c = str[i];
- if(c=='\t') { x = (x-left+PIXELTAB)/PIXELTAB*PIXELTAB+left; continue; };
- if(c=='\f') { glColor3ub(64,255,128); continue; };
- if(c==' ') { x += FONTH/2; continue; };
- c -= 33;
- if(c<0 || c>=95) continue;
-
- in_left = ((float) char_coords[c][0]) / 512.0f;
- in_top = ((float) char_coords[c][1]+2) / 512.0f;
- in_right = ((float) char_coords[c][2]) / 512.0f;
- in_bottom = ((float) char_coords[c][3]-2) / 512.0f;
-
- in_width = char_coords[c][2] - char_coords[c][0];
- in_height = char_coords[c][3] - char_coords[c][1];
-
- glBegin(GL_QUADS);
- glTexCoord2f(in_left, in_top ); glVertex2i(x, y);
- glTexCoord2f(in_right, in_top ); glVertex2i(x + in_width, y);
- glTexCoord2f(in_right, in_bottom); glVertex2i(x + in_width, y + in_height);
- glTexCoord2f(in_left, in_bottom); glVertex2i(x, y + in_height);
- glEnd();
-
- xtraverts += 4;
- x += in_width + 1;
- }
-}
-
-// also Don's code, so goes in here too :)
-
-void draw_envbox_aux(float s0, float t0, int x0, int y0, int z0,
- float s1, float t1, int x1, int y1, int z1,
- float s2, float t2, int x2, int y2, int z2,
- float s3, float t3, int x3, int y3, int z3,
- int texture)
-{
- glBindTexture(GL_TEXTURE_2D, texture);
- glBegin(GL_QUADS);
- glTexCoord2f(s3, t3); glVertex3d(x3, y3, z3);
- glTexCoord2f(s2, t2); glVertex3d(x2, y2, z2);
- glTexCoord2f(s1, t1); glVertex3d(x1, y1, z1);
- glTexCoord2f(s0, t0); glVertex3d(x0, y0, z0);
- glEnd();
- xtraverts += 4;
-}
-
-void draw_envbox(int t, int w)
-{
- glDepthMask(GL_FALSE);
-
- draw_envbox_aux(1.0f, 1.0f, -w, -w, w,
- 0.0f, 1.0f, w, -w, w,
- 0.0f, 0.0f, w, -w, -w,
- 1.0f, 0.0f, -w, -w, -w, t);
-
- draw_envbox_aux(1.0f, 1.0f, +w, w, w,
- 0.0f, 1.0f, -w, w, w,
- 0.0f, 0.0f, -w, w, -w,
- 1.0f, 0.0f, +w, w, -w, t+1);
-
- draw_envbox_aux(0.0f, 0.0f, -w, -w, -w,
- 1.0f, 0.0f, -w, w, -w,
- 1.0f, 1.0f, -w, w, w,
- 0.0f, 1.0f, -w, -w, w, t+2);
-
- draw_envbox_aux(1.0f, 1.0f, +w, -w, w,
- 0.0f, 1.0f, +w, w, w,
- 0.0f, 0.0f, +w, w, -w,
- 1.0f, 0.0f, +w, -w, -w, t+3);
-
- draw_envbox_aux(0.0f, 1.0f, -w, w, w,
- 0.0f, 0.0f, +w, w, w,
- 1.0f, 0.0f, +w, -w, w,
- 1.0f, 1.0f, -w, -w, w, t+4);
-
- draw_envbox_aux(0.0f, 1.0f, +w, w, -w,
- 0.0f, 0.0f, -w, w, -w,
- 1.0f, 0.0f, -w, -w, -w,
- 1.0f, 1.0f, +w, -w, -w, t+5);
-
- glDepthMask(GL_TRUE);
-}
ADDED src/rendertext.cxx
Index: src/rendertext.cxx
==================================================================
--- /dev/null
+++ src/rendertext.cxx
@@ -0,0 +1,222 @@
+// rendertext.cpp: based on Don's gl_text.cpp
+
+#include "cube.h"
+
+short char_coords[96][4] =
+{
+ {0,0,25,64}, //!
+ {25,0,54,64}, //"
+ {54,0,107,64}, //#
+ {107,0,148,64}, //$
+ {148,0,217,64}, //%
+ {217,0,263,64}, //&
+ {263,0,280,64}, //'
+ {280,0,309,64}, //(
+ {309,0,338,64}, //)
+ {338,0,379,64}, //*
+ {379,0,432,64}, //+
+ {432,0,455,64}, //,
+ {455,0,484,64}, //-
+ {0,64,21,128}, //.
+ {23,64,52,128}, ///
+ {52,64,93,128}, //0
+ {93,64,133,128}, //1
+ {133,64,174,128}, //2
+ {174,64,215,128}, //3
+ {215,64,256,128}, //4
+ {256,64,296,128}, //5
+ {296,64,337,128}, //6
+ {337,64,378,128}, //7
+ {378,64,419,128}, //8
+ {419,64,459,128}, //9
+ {459,64,488,128}, //:
+ {0,128,29,192}, //;
+ {29,128,81,192}, //<
+ {81,128,134,192}, //=
+ {134,128,186,192}, //>
+ {186,128,221,192}, //?
+ {221,128,285,192}, //@
+ {285,128,329,192}, //A
+ {329,128,373,192}, //B
+ {373,128,418,192}, //C
+ {418,128,467,192}, //D
+ {0,192,40,256}, //E
+ {40,192,77,256}, //F
+ {77,192,127,256}, //G
+ {127,192,175,256}, //H
+ {175,192,202,256}, //I
+ {202,192,231,256}, //J
+ {231,192,275,256}, //K
+ {275,192,311,256}, //L
+ {311,192,365,256}, //M
+ {365,192,413,256}, //N
+ {413,192,463,256}, //O
+ {1,256,38,320}, //P
+ {38,256,89,320}, //Q
+ {89,256,133,320}, //R
+ {133,256,176,320}, //S
+ {177,256,216,320}, //T
+ {217,256,263,320}, //U
+ {263,256,307,320}, //V
+ {307,256,370,320}, //W
+ {370,256,414,320}, //X
+ {414,256,453,320}, //Y
+ {453,256,497,320}, //Z
+ {0,320,29,384}, //[
+ {29,320,58,384}, //"\"
+ {59,320,87,384}, //]
+ {87,320,139,384}, //^
+ {139,320,180,384}, //_
+ {180,320,221,384}, //`
+ {221,320,259,384}, //a
+ {259,320,299,384}, //b
+ {299,320,332,384}, //c
+ {332,320,372,384}, //d
+ {372,320,411,384}, //e
+ {411,320,433,384}, //f
+ {435,320,473,384}, //g
+ {0,384,40,448}, //h
+ {40,384,56,448}, //i
+ {58,384,80,448}, //j
+ {80,384,118,448}, //k
+ {118,384,135,448}, //l
+ {135,384,197,448}, //m
+ {197,384,238,448}, //n
+ {238,384,277,448}, //o
+ {277,384,317,448}, //p
+ {317,384,356,448}, //q
+ {357,384,384,448}, //r
+ {385,384,417,448}, //s
+ {417,384,442,448}, //t
+ {443,384,483,448}, //u
+ {0,448,38,512}, //v
+ {38,448,90,512}, //w
+ {90,448,128,512}, //x
+ {128,448,166,512}, //y
+ {166,448,200,512}, //z
+ {200,448,241,512}, //{
+ {241,448,270,512}, //|
+ {270,448,310,512}, //}
+ {310,448,363,512}, //~
+};
+
+int text_width(char *str)
+{
+ int x = 0;
+ for (int i = 0; str[i] != 0; i++)
+ {
+ int c = str[i];
+ if(c=='\t') { x = (x+PIXELTAB)/PIXELTAB*PIXELTAB; continue; };
+ if(c=='\f') continue;
+ if(c==' ') { x += FONTH/2; continue; };
+ c -= 33;
+ if(c<0 || c>=95) continue;
+ int in_width = char_coords[c][2] - char_coords[c][0];
+ x += in_width + 1;
+ }
+ return x;
+}
+
+
+void draw_textf(char *fstr, int left, int top, int gl_num, ...)
+{
+ sprintf_sdlv(str, gl_num, fstr);
+ draw_text(str, left, top, gl_num);
+};
+
+void draw_text(char *str, int left, int top, int gl_num)
+{
+ glBlendFunc(GL_ONE, GL_ONE);
+ glBindTexture(GL_TEXTURE_2D, gl_num);
+ glColor3ub(255,255,255);
+
+ int x = left;
+ int y = top;
+
+ int i;
+ float in_left, in_top, in_right, in_bottom;
+ int in_width, in_height;
+
+ for (i = 0; str[i] != 0; i++)
+ {
+ int c = str[i];
+ if(c=='\t') { x = (x-left+PIXELTAB)/PIXELTAB*PIXELTAB+left; continue; };
+ if(c=='\f') { glColor3ub(64,255,128); continue; };
+ if(c==' ') { x += FONTH/2; continue; };
+ c -= 33;
+ if(c<0 || c>=95) continue;
+
+ in_left = ((float) char_coords[c][0]) / 512.0f;
+ in_top = ((float) char_coords[c][1]+2) / 512.0f;
+ in_right = ((float) char_coords[c][2]) / 512.0f;
+ in_bottom = ((float) char_coords[c][3]-2) / 512.0f;
+
+ in_width = char_coords[c][2] - char_coords[c][0];
+ in_height = char_coords[c][3] - char_coords[c][1];
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(in_left, in_top ); glVertex2i(x, y);
+ glTexCoord2f(in_right, in_top ); glVertex2i(x + in_width, y);
+ glTexCoord2f(in_right, in_bottom); glVertex2i(x + in_width, y + in_height);
+ glTexCoord2f(in_left, in_bottom); glVertex2i(x, y + in_height);
+ glEnd();
+
+ xtraverts += 4;
+ x += in_width + 1;
+ }
+}
+
+// also Don's code, so goes in here too :)
+
+void draw_envbox_aux(float s0, float t0, int x0, int y0, int z0,
+ float s1, float t1, int x1, int y1, int z1,
+ float s2, float t2, int x2, int y2, int z2,
+ float s3, float t3, int x3, int y3, int z3,
+ int texture)
+{
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glBegin(GL_QUADS);
+ glTexCoord2f(s3, t3); glVertex3d(x3, y3, z3);
+ glTexCoord2f(s2, t2); glVertex3d(x2, y2, z2);
+ glTexCoord2f(s1, t1); glVertex3d(x1, y1, z1);
+ glTexCoord2f(s0, t0); glVertex3d(x0, y0, z0);
+ glEnd();
+ xtraverts += 4;
+}
+
+void draw_envbox(int t, int w)
+{
+ glDepthMask(GL_FALSE);
+
+ draw_envbox_aux(1.0f, 1.0f, -w, -w, w,
+ 0.0f, 1.0f, w, -w, w,
+ 0.0f, 0.0f, w, -w, -w,
+ 1.0f, 0.0f, -w, -w, -w, t);
+
+ draw_envbox_aux(1.0f, 1.0f, +w, w, w,
+ 0.0f, 1.0f, -w, w, w,
+ 0.0f, 0.0f, -w, w, -w,
+ 1.0f, 0.0f, +w, w, -w, t+1);
+
+ draw_envbox_aux(0.0f, 0.0f, -w, -w, -w,
+ 1.0f, 0.0f, -w, w, -w,
+ 1.0f, 1.0f, -w, w, w,
+ 0.0f, 1.0f, -w, -w, w, t+2);
+
+ draw_envbox_aux(1.0f, 1.0f, +w, -w, w,
+ 0.0f, 1.0f, +w, w, w,
+ 0.0f, 0.0f, +w, w, -w,
+ 1.0f, 0.0f, +w, -w, -w, t+3);
+
+ draw_envbox_aux(0.0f, 1.0f, -w, w, w,
+ 0.0f, 0.0f, +w, w, w,
+ 1.0f, 0.0f, +w, -w, w,
+ 1.0f, 1.0f, -w, -w, w, t+4);
+
+ draw_envbox_aux(0.0f, 1.0f, +w, w, -w,
+ 0.0f, 0.0f, -w, w, -w,
+ 1.0f, 0.0f, -w, -w, -w,
+ 1.0f, 1.0f, +w, -w, -w, t+5);
+
+ glDepthMask(GL_TRUE);
+}
DELETED src/rndmap.cpp
Index: src/rndmap.cpp
==================================================================
--- src/rndmap.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// rndmap.cpp: perlin noise landscape generation and some experimental random map stuff, currently not used
-
-#include "cube.h"
-
-float noise(int x, int y, int seed)
-{
- int n = x+y*57;
- n = (n<<13)^n;
- return 1.0f-((n*(n*n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0f;
-}
-
-float smoothednoise(int x, int y, int seed)
-{
- float corners = (noise(x-1, y-1, seed)+noise(x+1, y-1, seed)+noise(x-1, y+1, seed)+noise(x+1, y+1, seed))/16;
- float sides = (noise(x-1, y, seed)+noise(x+1, y, seed)+noise(x, y-1, seed)+noise(x, y+1, seed))/8;
- float center = noise(x, y, seed)/4;
- return corners+sides+center;
-}
-
-float interpolate(float a, float b, float x)
-{
- float ft = x*3.1415927f;
- float f = (1.0f-(float)cos(ft))*0.5f;
- return a*(1-f)+b*f;
-}
-
-float interpolatednoise(float x, float y, int seed)
-{
- int ix = (int)x;
- float fx = x-ix;
- int iy = (int)y;
- float fy = y-iy;
- float v1 = smoothednoise(ix, iy, seed);
- float v2 = smoothednoise(ix+1, iy, seed);
- float v3 = smoothednoise(ix, iy+1, seed);
- float v4 = smoothednoise(ix+1, iy+1, seed);
- float i1 = interpolate(v1, v2, fx);
- float i2 = interpolate(v3, v4, fy);
- return interpolate(i1, i2, fy);
-}
-
-float perlinnoise_2D(float x, float y, int seedstep, float pers)
-{
- float total = 0;
- int seed = 0;
- for(int i = 0; i<7; i++)
- {
- float frequency = (float)(2^i);
- float amplitude = (float)pow(pers, i);
- total += interpolatednoise(x*frequency, y*frequency, seed)*amplitude;
- seed += seedstep;
- }
- return total;
-}
-
-void perlinarea(block &b, int scale, int seed, int psize)
-{
- srand(seed);
- seed = rnd(10000);
- if(!scale) scale = 10;
- for(int x = b.x; x<=b.x+b.xs; x++) for(int y = b.y; y<=b.y+b.ys; y++)
- {
- sqr *s = S(x,y);
- if(!SOLID(s) && x!=b.x+b.xs && y!=b.y+b.ys) s->type = FHF;
- s->vdelta = (int)(perlinnoise_2D(x/((float)scale)+seed, y/((float)scale)+seed, 1000, 0.01f)*50+25);
- if(s->vdelta>128) s->vdelta = 0;
- };
-};
-
-
ADDED src/rndmap.cxx
Index: src/rndmap.cxx
==================================================================
--- /dev/null
+++ src/rndmap.cxx
@@ -0,0 +1,70 @@
+// rndmap.cpp: perlin noise landscape generation and some experimental random map stuff, currently not used
+
+#include "cube.h"
+
+float noise(int x, int y, int seed)
+{
+ int n = x+y*57;
+ n = (n<<13)^n;
+ return 1.0f-((n*(n*n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0f;
+}
+
+float smoothednoise(int x, int y, int seed)
+{
+ float corners = (noise(x-1, y-1, seed)+noise(x+1, y-1, seed)+noise(x-1, y+1, seed)+noise(x+1, y+1, seed))/16;
+ float sides = (noise(x-1, y, seed)+noise(x+1, y, seed)+noise(x, y-1, seed)+noise(x, y+1, seed))/8;
+ float center = noise(x, y, seed)/4;
+ return corners+sides+center;
+}
+
+float interpolate(float a, float b, float x)
+{
+ float ft = x*3.1415927f;
+ float f = (1.0f-(float)cos(ft))*0.5f;
+ return a*(1-f)+b*f;
+}
+
+float interpolatednoise(float x, float y, int seed)
+{
+ int ix = (int)x;
+ float fx = x-ix;
+ int iy = (int)y;
+ float fy = y-iy;
+ float v1 = smoothednoise(ix, iy, seed);
+ float v2 = smoothednoise(ix+1, iy, seed);
+ float v3 = smoothednoise(ix, iy+1, seed);
+ float v4 = smoothednoise(ix+1, iy+1, seed);
+ float i1 = interpolate(v1, v2, fx);
+ float i2 = interpolate(v3, v4, fy);
+ return interpolate(i1, i2, fy);
+}
+
+float perlinnoise_2D(float x, float y, int seedstep, float pers)
+{
+ float total = 0;
+ int seed = 0;
+ for(int i = 0; i<7; i++)
+ {
+ float frequency = (float)(2^i);
+ float amplitude = (float)pow(pers, i);
+ total += interpolatednoise(x*frequency, y*frequency, seed)*amplitude;
+ seed += seedstep;
+ }
+ return total;
+}
+
+void perlinarea(block &b, int scale, int seed, int psize)
+{
+ srand(seed);
+ seed = rnd(10000);
+ if(!scale) scale = 10;
+ for(int x = b.x; x<=b.x+b.xs; x++) for(int y = b.y; y<=b.y+b.ys; y++)
+ {
+ sqr *s = S(x,y);
+ if(!SOLID(s) && x!=b.x+b.xs && y!=b.y+b.ys) s->type = FHF;
+ s->vdelta = (int)(perlinnoise_2D(x/((float)scale)+seed, y/((float)scale)+seed, 1000, 0.01f)*50+25);
+ if(s->vdelta>128) s->vdelta = 0;
+ };
+};
+
+
DELETED src/savegamedemo.cpp
Index: src/savegamedemo.cpp
==================================================================
--- src/savegamedemo.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-// loading and saving of savegames & demos, dumps the spawn state of all mapents, the full state of all dynents (monsters + player)
-
-#include "cube.h"
-
-extern int islittleendian;
-
-gzFile f = NULL;
-bool demorecording = false;
-bool demoplayback = false;
-bool demoloading = false;
-dvector playerhistory;
-int democlientnum = 0;
-
-void startdemo();
-
-void gzput(int i) { gzputc(f, i); };
-void gzputi(int i) { gzwrite(f, &i, sizeof(int)); };
-void gzputv(vec &v) { gzwrite(f, &v, sizeof(vec)); };
-
-void gzcheck(int a, int b) { if(a!=b) fatal("savegame file corrupt (short)"); };
-int gzget() { char c = gzgetc(f); return c; };
-int gzgeti() { int i; gzcheck(gzread(f, &i, sizeof(int)), sizeof(int)); return i; };
-void gzgetv(vec &v) { gzcheck(gzread(f, &v, sizeof(vec)), sizeof(vec)); };
-
-void stop()
-{
- if(f)
- {
- if(demorecording) gzputi(-1);
- gzclose(f);
- };
- f = NULL;
- demorecording = false;
- demoplayback = false;
- demoloading = false;
- loopv(playerhistory) zapdynent(playerhistory[i]);
- playerhistory.setsize(0);
-};
-
-void stopifrecording() { if(demorecording) stop(); };
-
-void savestate(char *fn)
-{
- stop();
- f = gzopen(fn, "wb9");
- if(!f) { conoutf("could not write %s", fn); return; };
- gzwrite(f, (void *)"CUBESAVE", 8);
- gzputc(f, islittleendian);
- gzputi(SAVEGAMEVERSION);
- gzputi(sizeof(dynent));
- gzwrite(f, getclientmap(), _MAXDEFSTR);
- gzputi(gamemode);
- gzputi(ents.length());
- loopv(ents) gzputc(f, ents[i].spawned);
- gzwrite(f, player1, sizeof(dynent));
- dvector &monsters = getmonsters();
- gzputi(monsters.length());
- loopv(monsters) gzwrite(f, monsters[i], sizeof(dynent));
- gzputi(players.length());
- loopv(players)
- {
- gzput(players[i]==NULL);
- gzwrite(f, players[i], sizeof(dynent));
- };
-};
-
-void savegame(char *name)
-{
- if(!m_classicsp) { conoutf("can only save classic sp games"); return; };
- sprintf_sd(fn)("savegames/%s.csgz", name);
- savestate(fn);
- stop();
- conoutf("wrote %s", fn);
-};
-
-void loadstate(char *fn)
-{
- stop();
- if(multiplayer()) return;
- f = gzopen(fn, "rb9");
- if(!f) { conoutf("could not open %s", fn); return; };
-
- string buf;
- gzread(f, buf, 8);
- if(strncmp(buf, "CUBESAVE", 8)) goto out;
- if(gzgetc(f)!=islittleendian) goto out; // not supporting save->load accross incompatible architectures simpifies things a LOT
- if(gzgeti()!=SAVEGAMEVERSION || gzgeti()!=sizeof(dynent)) goto out;
- string mapname;
- gzread(f, mapname, _MAXDEFSTR);
- nextmode = gzgeti();
- changemap(mapname); // continue below once map has been loaded and client & server have updated
- return;
- out:
- conoutf("aborting: savegame/demo from a different version of cube or cpu architecture");
- stop();
-};
-
-void loadgame(char *name)
-{
- sprintf_sd(fn)("savegames/%s.csgz", name);
- loadstate(fn);
-};
-
-void loadgameout()
-{
- stop();
- conoutf("loadgame incomplete: savegame from a different version of this map");
-};
-
-void loadgamerest()
-{
- if(demoplayback || !f) return;
-
- if(gzgeti()!=ents.length()) return loadgameout();
- loopv(ents)
- {
- ents[i].spawned = gzgetc(f)!=0;
- if(ents[i].type==CARROT && !ents[i].spawned) trigger(ents[i].attr1, ents[i].attr2, true);
- };
- restoreserverstate(ents);
-
- gzread(f, player1, sizeof(dynent));
- player1->lastaction = lastmillis;
-
- int nmonsters = gzgeti();
- dvector &monsters = getmonsters();
- if(nmonsters!=monsters.length()) return loadgameout();
- loopv(monsters)
- {
- gzread(f, monsters[i], sizeof(dynent));
- monsters[i]->enemy = player1; // lazy, could save id of enemy instead
- monsters[i]->lastaction = monsters[i]->trigger = lastmillis+500; // also lazy, but no real noticable effect on game
- if(monsters[i]->state==CS_DEAD) monsters[i]->lastaction = 0;
- };
- restoremonsterstate();
-
- int nplayers = gzgeti();
- loopi(nplayers) if(!gzget())
- {
- dynent *d = getclient(i);
- assert(d);
- gzread(f, d, sizeof(dynent));
- };
-
- conoutf("savegame restored");
- if(demoloading) startdemo(); else stop();
-};
-
-// demo functions
-
-int starttime = 0;
-int playbacktime = 0;
-int ddamage, bdamage;
-vec dorig;
-
-void record(char *name)
-{
- if(m_sp) { conoutf("cannot record singleplayer games"); return; };
- int cn = getclientnum();
- if(cn<0) return;
- sprintf_sd(fn)("demos/%s.cdgz", name);
- savestate(fn);
- gzputi(cn);
- conoutf("started recording demo to %s", fn);
- demorecording = true;
- starttime = lastmillis;
- ddamage = bdamage = 0;
-};
-
-void demodamage(int damage, vec &o) { ddamage = damage; dorig = o; };
-void demoblend(int damage) { bdamage = damage; };
-
-void incomingdemodata(uchar *buf, int len, bool extras)
-{
- if(!demorecording) return;
- gzputi(lastmillis-starttime);
- gzputi(len);
- gzwrite(f, buf, len);
- gzput(extras);
- if(extras)
- {
- gzput(player1->gunselect);
- gzput(player1->lastattackgun);
- gzputi(player1->lastaction-starttime);
- gzputi(player1->gunwait);
- gzputi(player1->health);
- gzputi(player1->armour);
- gzput(player1->armourtype);
- loopi(NUMGUNS) gzput(player1->ammo[i]);
- gzput(player1->state);
- gzputi(bdamage);
- bdamage = 0;
- gzputi(ddamage);
- if(ddamage) { gzputv(dorig); ddamage = 0; };
- // FIXME: add all other client state which is not send through the network
- };
-};
-
-void demo(char *name)
-{
- sprintf_sd(fn)("demos/%s.cdgz", name);
- loadstate(fn);
- demoloading = true;
-};
-
-void stopreset()
-{
- conoutf("demo stopped (%d msec elapsed)", lastmillis-starttime);
- stop();
- loopv(players) zapdynent(players[i]);
- disconnect(0, 0);
-};
-
-VAR(demoplaybackspeed, 10, 100, 1000);
-int scaletime(int t) { return (int)(t*(100.0f/demoplaybackspeed))+starttime; };
-
-void readdemotime()
-{
- if(gzeof(f) || (playbacktime = gzgeti())==-1)
- {
- stopreset();
- return;
- };
- playbacktime = scaletime(playbacktime);
-};
-
-void startdemo()
-{
- democlientnum = gzgeti();
- demoplayback = true;
- starttime = lastmillis;
- conoutf("now playing demo");
- dynent *d = getclient(democlientnum);
- assert(d);
- *d = *player1;
- readdemotime();
-};
-
-VAR(demodelaymsec, 0, 120, 500);
-
-void catmulrom(vec &z, vec &a, vec &b, vec &c, float s, vec &dest) // spline interpolation
-{
- vec t1 = b, t2 = c;
-
- vsub(t1, z); vmul(t1, 0.5f)
- vsub(t2, a); vmul(t2, 0.5f);
-
- float s2 = s*s;
- float s3 = s*s2;
-
- dest = a;
- vec t = b;
-
- vmul(dest, 2*s3 - 3*s2 + 1);
- vmul(t, -2*s3 + 3*s2); vadd(dest, t);
- vmul(t1, s3 - 2*s2 + s); vadd(dest, t1);
- vmul(t2, s3 - s2); vadd(dest, t2);
-};
-
-void fixwrap(dynent *a, dynent *b)
-{
- while(b->yaw-a->yaw>180) a->yaw += 360;
- while(b->yaw-a->yaw<-180) a->yaw -= 360;
-};
-
-void demoplaybackstep()
-{
- while(demoplayback && lastmillis>=playbacktime)
- {
- int len = gzgeti();
- if(len<1 || len>MAXTRANS)
- {
- conoutf("error: huge packet during demo play (%d)", len);
- stopreset();
- return;
- };
- uchar buf[MAXTRANS];
- gzread(f, buf, len);
- localservertoclient(buf, len); // update game state
-
- dynent *target = players[democlientnum];
- assert(target);
-
- int extras;
- if(extras = gzget()) // read additional client side state not present in normal network stream
- {
- target->gunselect = gzget();
- target->lastattackgun = gzget();
- target->lastaction = scaletime(gzgeti());
- target->gunwait = gzgeti();
- target->health = gzgeti();
- target->armour = gzgeti();
- target->armourtype = gzget();
- loopi(NUMGUNS) target->ammo[i] = gzget();
- target->state = gzget();
- target->lastmove = playbacktime;
- if(bdamage = gzgeti()) damageblend(bdamage);
- if(ddamage = gzgeti()) { gzgetv(dorig); particle_splash(3, ddamage, 1000, dorig); };
- // FIXME: set more client state here
- };
-
- // insert latest copy of player into history
- if(extras && (playerhistory.empty() || playerhistory.last()->lastupdate!=playbacktime))
- {
- dynent *d = newdynent();
- *d = *target;
- d->lastupdate = playbacktime;
- playerhistory.add(d);
- if(playerhistory.length()>20)
- {
- zapdynent(playerhistory[0]);
- playerhistory.remove(0);
- };
- };
-
- readdemotime();
- };
-
- if(demoplayback)
- {
- int itime = lastmillis-demodelaymsec;
- loopvrev(playerhistory) if(playerhistory[i]->lastupdate=0) z = playerhistory[i-1];
- //if(a==z || b==c) printf("* %d\n", lastmillis);
- float bf = (itime-a->lastupdate)/(float)(b->lastupdate-a->lastupdate);
- fixwrap(a, player1);
- fixwrap(c, player1);
- fixwrap(z, player1);
- vdist(dist, v, z->o, c->o);
- if(dist<16) // if teleport or spawn, dont't interpolate
- {
- catmulrom(z->o, a->o, b->o, c->o, bf, player1->o);
- catmulrom(*(vec *)&z->yaw, *(vec *)&a->yaw, *(vec *)&b->yaw, *(vec *)&c->yaw, bf, *(vec *)&player1->yaw);
- };
- fixplayer1range();
- };
- break;
- };
- //if(player1->state!=CS_DEAD) showscores(false);
- };
-};
-
-void stopn() { if(demoplayback) stopreset(); else stop(); conoutf("demo stopped"); };
-
-COMMAND(record, ARG_1STR);
-COMMAND(demo, ARG_1STR);
-COMMANDN(stop, stopn, ARG_NONE);
-
-COMMAND(savegame, ARG_1STR);
-COMMAND(loadgame, ARG_1STR);
ADDED src/savegamedemo.cxx
Index: src/savegamedemo.cxx
==================================================================
--- /dev/null
+++ src/savegamedemo.cxx
@@ -0,0 +1,360 @@
+// loading and saving of savegames & demos, dumps the spawn state of all mapents, the full state of all dynents (monsters + player)
+
+#include "cube.h"
+
+extern int islittleendian;
+
+gzFile f = NULL;
+bool demorecording = false;
+bool demoplayback = false;
+bool demoloading = false;
+dvector playerhistory;
+int democlientnum = 0;
+
+void startdemo();
+
+void gzput(int i) { gzputc(f, i); };
+void gzputi(int i) { gzwrite(f, &i, sizeof(int)); };
+void gzputv(vec &v) { gzwrite(f, &v, sizeof(vec)); };
+
+void gzcheck(int a, int b) { if(a!=b) fatal("savegame file corrupt (short)"); };
+int gzget() { char c = gzgetc(f); return c; };
+int gzgeti() { int i; gzcheck(gzread(f, &i, sizeof(int)), sizeof(int)); return i; };
+void gzgetv(vec &v) { gzcheck(gzread(f, &v, sizeof(vec)), sizeof(vec)); };
+
+void stop()
+{
+ if(f)
+ {
+ if(demorecording) gzputi(-1);
+ gzclose(f);
+ };
+ f = NULL;
+ demorecording = false;
+ demoplayback = false;
+ demoloading = false;
+ loopv(playerhistory) zapdynent(playerhistory[i]);
+ playerhistory.setsize(0);
+};
+
+void stopifrecording() { if(demorecording) stop(); };
+
+void savestate(char *fn)
+{
+ stop();
+ f = gzopen(fn, "wb9");
+ if(!f) { conoutf("could not write %s", fn); return; };
+ gzwrite(f, (void *)"CUBESAVE", 8);
+ gzputc(f, islittleendian);
+ gzputi(SAVEGAMEVERSION);
+ gzputi(sizeof(dynent));
+ gzwrite(f, getclientmap(), _MAXDEFSTR);
+ gzputi(gamemode);
+ gzputi(ents.length());
+ loopv(ents) gzputc(f, ents[i].spawned);
+ gzwrite(f, player1, sizeof(dynent));
+ dvector &monsters = getmonsters();
+ gzputi(monsters.length());
+ loopv(monsters) gzwrite(f, monsters[i], sizeof(dynent));
+ gzputi(players.length());
+ loopv(players)
+ {
+ gzput(players[i]==NULL);
+ gzwrite(f, players[i], sizeof(dynent));
+ };
+};
+
+void savegame(char *name)
+{
+ if(!m_classicsp) { conoutf("can only save classic sp games"); return; };
+ sprintf_sd(fn)("savegames/%s.csgz", name);
+ savestate(fn);
+ stop();
+ conoutf("wrote %s", fn);
+};
+
+void loadstate(char *fn)
+{
+ stop();
+ if(multiplayer()) return;
+ f = gzopen(fn, "rb9");
+ if(!f) { conoutf("could not open %s", fn); return; };
+
+ string buf;
+ gzread(f, buf, 8);
+ if(strncmp(buf, "CUBESAVE", 8)) goto out;
+ if(gzgetc(f)!=islittleendian) goto out; // not supporting save->load accross incompatible architectures simpifies things a LOT
+ if(gzgeti()!=SAVEGAMEVERSION || gzgeti()!=sizeof(dynent)) goto out;
+ string mapname;
+ gzread(f, mapname, _MAXDEFSTR);
+ nextmode = gzgeti();
+ changemap(mapname); // continue below once map has been loaded and client & server have updated
+ return;
+ out:
+ conoutf("aborting: savegame/demo from a different version of cube or cpu architecture");
+ stop();
+};
+
+void loadgame(char *name)
+{
+ sprintf_sd(fn)("savegames/%s.csgz", name);
+ loadstate(fn);
+};
+
+void loadgameout()
+{
+ stop();
+ conoutf("loadgame incomplete: savegame from a different version of this map");
+};
+
+void loadgamerest()
+{
+ if(demoplayback || !f) return;
+
+ if(gzgeti()!=ents.length()) return loadgameout();
+ loopv(ents)
+ {
+ ents[i].spawned = gzgetc(f)!=0;
+ if(ents[i].type==CARROT && !ents[i].spawned) trigger(ents[i].attr1, ents[i].attr2, true);
+ };
+ restoreserverstate(ents);
+
+ gzread(f, player1, sizeof(dynent));
+ player1->lastaction = lastmillis;
+
+ int nmonsters = gzgeti();
+ dvector &monsters = getmonsters();
+ if(nmonsters!=monsters.length()) return loadgameout();
+ loopv(monsters)
+ {
+ gzread(f, monsters[i], sizeof(dynent));
+ monsters[i]->enemy = player1; // lazy, could save id of enemy instead
+ monsters[i]->lastaction = monsters[i]->trigger = lastmillis+500; // also lazy, but no real noticable effect on game
+ if(monsters[i]->state==CS_DEAD) monsters[i]->lastaction = 0;
+ };
+ restoremonsterstate();
+
+ int nplayers = gzgeti();
+ loopi(nplayers) if(!gzget())
+ {
+ dynent *d = getclient(i);
+ assert(d);
+ gzread(f, d, sizeof(dynent));
+ };
+
+ conoutf("savegame restored");
+ if(demoloading) startdemo(); else stop();
+};
+
+// demo functions
+
+int starttime = 0;
+int playbacktime = 0;
+int ddamage, bdamage;
+vec dorig;
+
+void record(char *name)
+{
+ if(m_sp) { conoutf("cannot record singleplayer games"); return; };
+ int cn = getclientnum();
+ if(cn<0) return;
+ sprintf_sd(fn)("demos/%s.cdgz", name);
+ savestate(fn);
+ gzputi(cn);
+ conoutf("started recording demo to %s", fn);
+ demorecording = true;
+ starttime = lastmillis;
+ ddamage = bdamage = 0;
+};
+
+void demodamage(int damage, vec &o) { ddamage = damage; dorig = o; };
+void demoblend(int damage) { bdamage = damage; };
+
+void incomingdemodata(uchar *buf, int len, bool extras)
+{
+ if(!demorecording) return;
+ gzputi(lastmillis-starttime);
+ gzputi(len);
+ gzwrite(f, buf, len);
+ gzput(extras);
+ if(extras)
+ {
+ gzput(player1->gunselect);
+ gzput(player1->lastattackgun);
+ gzputi(player1->lastaction-starttime);
+ gzputi(player1->gunwait);
+ gzputi(player1->health);
+ gzputi(player1->armour);
+ gzput(player1->armourtype);
+ loopi(NUMGUNS) gzput(player1->ammo[i]);
+ gzput(player1->state);
+ gzputi(bdamage);
+ bdamage = 0;
+ gzputi(ddamage);
+ if(ddamage) { gzputv(dorig); ddamage = 0; };
+ // FIXME: add all other client state which is not send through the network
+ };
+};
+
+void demo(char *name)
+{
+ sprintf_sd(fn)("demos/%s.cdgz", name);
+ loadstate(fn);
+ demoloading = true;
+};
+
+void stopreset()
+{
+ conoutf("demo stopped (%d msec elapsed)", lastmillis-starttime);
+ stop();
+ loopv(players) zapdynent(players[i]);
+ disconnect(0, 0);
+};
+
+VAR(demoplaybackspeed, 10, 100, 1000);
+int scaletime(int t) { return (int)(t*(100.0f/demoplaybackspeed))+starttime; };
+
+void readdemotime()
+{
+ if(gzeof(f) || (playbacktime = gzgeti())==-1)
+ {
+ stopreset();
+ return;
+ };
+ playbacktime = scaletime(playbacktime);
+};
+
+void startdemo()
+{
+ democlientnum = gzgeti();
+ demoplayback = true;
+ starttime = lastmillis;
+ conoutf("now playing demo");
+ dynent *d = getclient(democlientnum);
+ assert(d);
+ *d = *player1;
+ readdemotime();
+};
+
+VAR(demodelaymsec, 0, 120, 500);
+
+void catmulrom(vec &z, vec &a, vec &b, vec &c, float s, vec &dest) // spline interpolation
+{
+ vec t1 = b, t2 = c;
+
+ vsub(t1, z); vmul(t1, 0.5f)
+ vsub(t2, a); vmul(t2, 0.5f);
+
+ float s2 = s*s;
+ float s3 = s*s2;
+
+ dest = a;
+ vec t = b;
+
+ vmul(dest, 2*s3 - 3*s2 + 1);
+ vmul(t, -2*s3 + 3*s2); vadd(dest, t);
+ vmul(t1, s3 - 2*s2 + s); vadd(dest, t1);
+ vmul(t2, s3 - s2); vadd(dest, t2);
+};
+
+void fixwrap(dynent *a, dynent *b)
+{
+ while(b->yaw-a->yaw>180) a->yaw += 360;
+ while(b->yaw-a->yaw<-180) a->yaw -= 360;
+};
+
+void demoplaybackstep()
+{
+ while(demoplayback && lastmillis>=playbacktime)
+ {
+ int len = gzgeti();
+ if(len<1 || len>MAXTRANS)
+ {
+ conoutf("error: huge packet during demo play (%d)", len);
+ stopreset();
+ return;
+ };
+ uchar buf[MAXTRANS];
+ gzread(f, buf, len);
+ localservertoclient(buf, len); // update game state
+
+ dynent *target = players[democlientnum];
+ assert(target);
+
+ int extras;
+ if(extras = gzget()) // read additional client side state not present in normal network stream
+ {
+ target->gunselect = gzget();
+ target->lastattackgun = gzget();
+ target->lastaction = scaletime(gzgeti());
+ target->gunwait = gzgeti();
+ target->health = gzgeti();
+ target->armour = gzgeti();
+ target->armourtype = gzget();
+ loopi(NUMGUNS) target->ammo[i] = gzget();
+ target->state = gzget();
+ target->lastmove = playbacktime;
+ if(bdamage = gzgeti()) damageblend(bdamage);
+ if(ddamage = gzgeti()) { gzgetv(dorig); particle_splash(3, ddamage, 1000, dorig); };
+ // FIXME: set more client state here
+ };
+
+ // insert latest copy of player into history
+ if(extras && (playerhistory.empty() || playerhistory.last()->lastupdate!=playbacktime))
+ {
+ dynent *d = newdynent();
+ *d = *target;
+ d->lastupdate = playbacktime;
+ playerhistory.add(d);
+ if(playerhistory.length()>20)
+ {
+ zapdynent(playerhistory[0]);
+ playerhistory.remove(0);
+ };
+ };
+
+ readdemotime();
+ };
+
+ if(demoplayback)
+ {
+ int itime = lastmillis-demodelaymsec;
+ loopvrev(playerhistory) if(playerhistory[i]->lastupdate=0) z = playerhistory[i-1];
+ //if(a==z || b==c) printf("* %d\n", lastmillis);
+ float bf = (itime-a->lastupdate)/(float)(b->lastupdate-a->lastupdate);
+ fixwrap(a, player1);
+ fixwrap(c, player1);
+ fixwrap(z, player1);
+ vdist(dist, v, z->o, c->o);
+ if(dist<16) // if teleport or spawn, dont't interpolate
+ {
+ catmulrom(z->o, a->o, b->o, c->o, bf, player1->o);
+ catmulrom(*(vec *)&z->yaw, *(vec *)&a->yaw, *(vec *)&b->yaw, *(vec *)&c->yaw, bf, *(vec *)&player1->yaw);
+ };
+ fixplayer1range();
+ };
+ break;
+ };
+ //if(player1->state!=CS_DEAD) showscores(false);
+ };
+};
+
+void stopn() { if(demoplayback) stopreset(); else stop(); conoutf("demo stopped"); };
+
+COMMAND(record, ARG_1STR);
+COMMAND(demo, ARG_1STR);
+COMMANDN(stop, stopn, ARG_NONE);
+
+COMMAND(savegame, ARG_1STR);
+COMMAND(loadgame, ARG_1STR);
DELETED src/server.cpp
Index: src/server.cpp
==================================================================
--- src/server.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-// server.cpp: little more than enhanced multicaster
-// runs dedicated or as client coroutine
-
-#include "cube.h"
-
-enum { ST_EMPTY, ST_LOCAL, ST_TCPIP };
-
-struct client // server side version of "dynent" type
-{
- int type;
- ENetPeer *peer;
- string hostname;
- string mapvote;
- string name;
- int modevote;
-};
-
-vector clients;
-
-int maxclients = 8;
-string smapname;
-
-struct server_entity // server side version of "entity" type
-{
- bool spawned;
- int spawnsecs;
-};
-
-vector sents;
-
-bool notgotitems = true; // true when map has changed and waiting for clients to send item
-int mode = 0;
-
-void restoreserverstate(vector &ents) // hack: called from savegame code, only works in SP
-{
- loopv(sents)
- {
- sents[i].spawned = ents[i].spawned;
- sents[i].spawnsecs = 0;
- };
-};
-
-int interm = 0, minremain = 0, mapend = 0;
-bool mapreload = false;
-
-char *serverpassword = "";
-
-bool isdedicated;
-ENetHost * serverhost = NULL;
-int bsend = 0, brec = 0, laststatus = 0, lastsec = 0;
-
-#define MAXOBUF 100000
-
-void process(ENetPacket *packet, int sender);
-void multicast(ENetPacket *packet, int sender);
-void disconnect_client(int n, char *reason);
-
-void send(int n, ENetPacket *packet)
-{
- if(!packet) return;
- switch(clients[n].type)
- {
- case ST_TCPIP:
- {
- enet_peer_send(clients[n].peer, 0, packet);
- bsend += packet->dataLength;
- break;
- };
-
- case ST_LOCAL:
- localservertoclient(packet->data, packet->dataLength);
- break;
-
- };
-};
-
-void send2(bool rel, int cn, int a, int b)
-{
- ENetPacket *packet = enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, a);
- putint(p, b);
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- if(cn<0) process(packet, -1);
- else send(cn, packet);
- if(packet->referenceCount==0) enet_packet_destroy(packet);
-};
-
-void sendservmsg(char *msg)
-{
- ENetPacket *packet = enet_packet_create(NULL, _MAXDEFSTR+10, ENET_PACKET_FLAG_RELIABLE);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, SV_SERVMSG);
- sendstring(msg, p);
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- multicast(packet, -1);
- if(packet->referenceCount==0) enet_packet_destroy(packet);
-};
-
-void disconnect_client(int n, char *reason)
-{
- printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason);
- enet_peer_disconnect(clients[n].peer);
- clients[n].type = ST_EMPTY;
- send2(true, -1, SV_CDIS, n);
-};
-
-void resetitems() { sents.setsize(0); notgotitems = true; };
-
-void pickup(uint i, int sec, int sender) // server side item pickup, acknowledge first client that gets it
-{
- if(i>=(uint)sents.length()) return;
- if(sents[i].spawned)
- {
- sents[i].spawned = false;
- sents[i].spawnsecs = sec;
- send2(true, sender, SV_ITEMACC, i);
- };
-};
-
-void resetvotes()
-{
- loopv(clients) clients[i].mapvote[0] = 0;
-};
-
-bool vote(char *map, int reqmode, int sender)
-{
- strcpy_s(clients[sender].mapvote, map);
- clients[sender].modevote = reqmode;
- int yes = 0, no = 0;
- loopv(clients) if(clients[i].type!=ST_EMPTY)
- {
- if(clients[i].mapvote[0]) { if(strcmp(clients[i].mapvote, map)==0 && clients[i].modevote==reqmode) yes++; else no++; }
- else no++;
- };
- if(yes==1 && no==0) return true; // single player
- sprintf_sd(msg)("%s suggests %s on map %s (set map to vote)", clients[sender].name, modestr(reqmode), map);
- sendservmsg(msg);
- if(yes/(float)(yes+no) <= 0.5f) return false;
- sendservmsg("vote passed");
- resetvotes();
- return true;
-};
-
-// server side processing of updates: does very little and most state is tracked client only
-// could be extended to move more gameplay to server (at expense of lag)
-
-void process(ENetPacket * packet, int sender) // sender may be -1
-{
- if(ENET_NET_TO_HOST_16(*(ushort *)packet->data)!=packet->dataLength)
- {
- disconnect_client(sender, "packet length");
- return;
- };
-
- uchar *end = packet->data+packet->dataLength;
- uchar *p = packet->data+2;
- char text[MAXTRANS];
- int cn = -1, type;
-
- while(p=clients.length() || clients[cn].type==ST_EMPTY)
- {
- disconnect_client(sender, "client num");
- return;
- };
- int size = msgsizelookup(type);
- assert(size!=-1);
- loopi(size-2) getint(p);
- break;
- };
-
- case SV_SENDMAP:
- {
- sgetstr();
- int mapsize = getint(p);
- sendmaps(sender, text, mapsize, p);
- return;
- }
-
- case SV_RECVMAP:
- send(sender, recvmap(sender));
- return;
-
- case SV_EXT: // allows for new features that require no server updates
- {
- for(int n = getint(p); n; n--) getint(p);
- break;
- };
-
- default:
- {
- int size = msgsizelookup(type);
- if(size==-1) { disconnect_client(sender, "tag type"); return; };
- loopi(size-1) getint(p);
- };
- };
-
- if(p>end) { disconnect_client(sender, "end of packet"); return; };
- multicast(packet, sender);
-};
-
-void send_welcome(int n)
-{
- ENetPacket * packet = enet_packet_create (NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, SV_INITS2C);
- putint(p, n);
- putint(p, PROTOCOL_VERSION);
- putint(p, smapname[0]);
- sendstring(serverpassword, p);
- putint(p, clients.length()>maxclients);
- if(smapname[0])
- {
- putint(p, SV_MAPCHANGE);
- sendstring(smapname, p);
- putint(p, mode);
- putint(p, SV_ITEMLIST);
- loopv(sents) if(sents[i].spawned) putint(p, i);
- putint(p, -1);
- };
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- send(n, packet);
-};
-
-void multicast(ENetPacket *packet, int sender)
-{
- loopv(clients)
- {
- if(i==sender) continue;
- send(i, packet);
- };
-};
-
-void localclienttoserver(ENetPacket *packet)
-{
- process(packet, 0);
- if(!packet->referenceCount) enet_packet_destroy (packet);
-};
-
-client &addclient()
-{
- loopv(clients) if(clients[i].type==ST_EMPTY) return clients[i];
- return clients.add();
-};
-
-void checkintermission()
-{
- if(!minremain)
- {
- interm = lastsec+10;
- mapend = lastsec+1000;
- };
- send2(true, -1, SV_TIMEUP, minremain--);
-};
-
-void startintermission() { minremain = 0; checkintermission(); };
-
-void resetserverifempty()
-{
- loopv(clients) if(clients[i].type!=ST_EMPTY) return;
- clients.setsize(0);
- smapname[0] = 0;
- resetvotes();
- resetitems();
- mode = 0;
- mapreload = false;
- minremain = 10;
- mapend = lastsec+minremain*60;
- interm = 0;
-};
-
-int nonlocalclients = 0;
-int lastconnect = 0;
-
-void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in sp, or dedicated server loop
-{
- loopv(sents) // spawn entities when timer reached
- {
- if(sents[i].spawnsecs && (sents[i].spawnsecs -= seconds-lastsec)<=0)
- {
- sents[i].spawnsecs = 0;
- sents[i].spawned = true;
- send2(true, -1, SV_ITEMSPAWN, i);
- };
- };
-
- lastsec = seconds;
-
- if((mode>1 || (mode==0 && nonlocalclients)) && seconds>mapend-minremain*60) checkintermission();
- if(interm && seconds>interm)
- {
- interm = 0;
- loopv(clients) if(clients[i].type!=ST_EMPTY)
- {
- send2(true, i, SV_MAPRELOAD, 0); // ask a client to trigger map reload
- mapreload = true;
- break;
- };
- };
-
- resetserverifempty();
-
- if(!isdedicated) return; // below is network only
-
- int numplayers = 0;
- loopv(clients) if(clients[i].type!=ST_EMPTY) ++numplayers;
- serverms(mode, numplayers, minremain, smapname, seconds, clients.length()>=maxclients);
-
- if(seconds-laststatus>60) // display bandwidth stats, useful for server ops
- {
- nonlocalclients = 0;
- loopv(clients) if(clients[i].type==ST_TCPIP) nonlocalclients++;
- laststatus = seconds;
- if(nonlocalclients || bsend || brec) printf("status: %d remote clients, %.1f send, %.1f rec (K/sec)\n", nonlocalclients, bsend/60.0f/1024, brec/60.0f/1024);
- bsend = brec = 0;
- };
-
- ENetEvent event;
- if(enet_host_service(serverhost, &event, timeout) > 0)
- {
- switch(event.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- {
- client &c = addclient();
- c.type = ST_TCPIP;
- c.peer = event.peer;
- c.peer->data = (void *)(&c-&clients[0]);
- char hn[1024];
- strcpy_s(c.hostname, (enet_address_get_host(&c.peer->address, hn, sizeof(hn))==0) ? hn : "localhost");
- printf("client connected (%s)\n", c.hostname);
- send_welcome(lastconnect = &c-&clients[0]);
- break;
- }
- case ENET_EVENT_TYPE_RECEIVE:
- brec += event.packet->dataLength;
- process(event.packet, (int)event.peer->data);
- if(event.packet->referenceCount==0) enet_packet_destroy(event.packet);
- break;
-
- case ENET_EVENT_TYPE_DISCONNECT:
- if((int)event.peer->data<0) break;
- printf("disconnected client (%s)\n", clients[(int)event.peer->data].hostname);
- clients[(int)event.peer->data].type = ST_EMPTY;
- send2(true, -1, SV_CDIS, (int)event.peer->data);
- event.peer->data = (void *)-1;
- break;
- };
-
- if(numplayers>maxclients)
- {
- disconnect_client(lastconnect, "maxclients reached");
- };
- };
- #ifndef WIN32
- fflush(stdout);
- #endif
-};
-
-void cleanupserver()
-{
- if(serverhost) enet_host_destroy(serverhost);
-};
-
-void localdisconnect()
-{
- loopv(clients) if(clients[i].type==ST_LOCAL) clients[i].type = ST_EMPTY;
-};
-
-void localconnect()
-{
- client &c = addclient();
- c.type = ST_LOCAL;
- strcpy_s(c.hostname, "local");
- send_welcome(&c-&clients[0]);
-};
-
-void initserver(bool dedicated, int uprate, char *sdesc, char *ip, char *master, char *passwd, int maxcl)
-{
- serverpassword = passwd;
- maxclients = maxcl;
- servermsinit(master ? master : "wouter.fov120.com/cube/masterserver/", sdesc, dedicated);
-
- if(isdedicated = dedicated)
- {
- ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
- if(*ip && enet_address_set_host(&address, ip)<0) printf("WARNING: server ip not resolved");
- serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate);
- if(!serverhost) fatal("could not create server host\n");
- loopi(MAXCLIENTS) serverhost->peers[i].data = (void *)-1;
- };
-
- resetserverifempty();
-
- if(isdedicated) // do not return, this becomes main loop
- {
- #ifdef WIN32
- SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
- #endif
- printf("dedicated server started, waiting for clients...\nCtrl-C to exit\n\n");
- atexit(cleanupserver);
- atexit(enet_deinitialize);
- for(;;) serverslice(/*enet_time_get_sec()*/time(NULL), 5);
- };
-};
ADDED src/server.cxx
Index: src/server.cxx
==================================================================
--- /dev/null
+++ src/server.cxx
@@ -0,0 +1,468 @@
+// server.cpp: little more than enhanced multicaster
+// runs dedicated or as client coroutine
+
+#include "cube.h"
+
+enum { ST_EMPTY, ST_LOCAL, ST_TCPIP };
+
+struct client // server side version of "dynent" type
+{
+ int type;
+ ENetPeer *peer;
+ string hostname;
+ string mapvote;
+ string name;
+ int modevote;
+};
+
+vector clients;
+
+int maxclients = 8;
+string smapname;
+
+struct server_entity // server side version of "entity" type
+{
+ bool spawned;
+ int spawnsecs;
+};
+
+vector sents;
+
+bool notgotitems = true; // true when map has changed and waiting for clients to send item
+int mode = 0;
+
+void restoreserverstate(vector &ents) // hack: called from savegame code, only works in SP
+{
+ loopv(sents)
+ {
+ sents[i].spawned = ents[i].spawned;
+ sents[i].spawnsecs = 0;
+ };
+};
+
+int interm = 0, minremain = 0, mapend = 0;
+bool mapreload = false;
+
+char *serverpassword = "";
+
+bool isdedicated;
+ENetHost * serverhost = NULL;
+int bsend = 0, brec = 0, laststatus = 0, lastsec = 0;
+
+#define MAXOBUF 100000
+
+void process(ENetPacket *packet, int sender);
+void multicast(ENetPacket *packet, int sender);
+void disconnect_client(int n, char *reason);
+
+void send(int n, ENetPacket *packet)
+{
+ if(!packet) return;
+ switch(clients[n].type)
+ {
+ case ST_TCPIP:
+ {
+ enet_peer_send(clients[n].peer, 0, packet);
+ bsend += packet->dataLength;
+ break;
+ };
+
+ case ST_LOCAL:
+ localservertoclient(packet->data, packet->dataLength);
+ break;
+
+ };
+};
+
+void send2(bool rel, int cn, int a, int b)
+{
+ ENetPacket *packet = enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, a);
+ putint(p, b);
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ if(cn<0) process(packet, -1);
+ else send(cn, packet);
+ if(packet->referenceCount==0) enet_packet_destroy(packet);
+};
+
+void sendservmsg(char *msg)
+{
+ ENetPacket *packet = enet_packet_create(NULL, _MAXDEFSTR+10, ENET_PACKET_FLAG_RELIABLE);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, SV_SERVMSG);
+ sendstring(msg, p);
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ multicast(packet, -1);
+ if(packet->referenceCount==0) enet_packet_destroy(packet);
+};
+
+void disconnect_client(int n, char *reason)
+{
+ printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason);
+ enet_peer_disconnect(clients[n].peer);
+ clients[n].type = ST_EMPTY;
+ send2(true, -1, SV_CDIS, n);
+};
+
+void resetitems() { sents.setsize(0); notgotitems = true; };
+
+void pickup(uint i, int sec, int sender) // server side item pickup, acknowledge first client that gets it
+{
+ if(i>=(uint)sents.length()) return;
+ if(sents[i].spawned)
+ {
+ sents[i].spawned = false;
+ sents[i].spawnsecs = sec;
+ send2(true, sender, SV_ITEMACC, i);
+ };
+};
+
+void resetvotes()
+{
+ loopv(clients) clients[i].mapvote[0] = 0;
+};
+
+bool vote(char *map, int reqmode, int sender)
+{
+ strcpy_s(clients[sender].mapvote, map);
+ clients[sender].modevote = reqmode;
+ int yes = 0, no = 0;
+ loopv(clients) if(clients[i].type!=ST_EMPTY)
+ {
+ if(clients[i].mapvote[0]) { if(strcmp(clients[i].mapvote, map)==0 && clients[i].modevote==reqmode) yes++; else no++; }
+ else no++;
+ };
+ if(yes==1 && no==0) return true; // single player
+ sprintf_sd(msg)("%s suggests %s on map %s (set map to vote)", clients[sender].name, modestr(reqmode), map);
+ sendservmsg(msg);
+ if(yes/(float)(yes+no) <= 0.5f) return false;
+ sendservmsg("vote passed");
+ resetvotes();
+ return true;
+};
+
+// server side processing of updates: does very little and most state is tracked client only
+// could be extended to move more gameplay to server (at expense of lag)
+
+void process(ENetPacket * packet, int sender) // sender may be -1
+{
+ if(ENET_NET_TO_HOST_16(*(ushort *)packet->data)!=packet->dataLength)
+ {
+ disconnect_client(sender, "packet length");
+ return;
+ };
+
+ uchar *end = packet->data+packet->dataLength;
+ uchar *p = packet->data+2;
+ char text[MAXTRANS];
+ int cn = -1, type;
+
+ while(p=clients.length() || clients[cn].type==ST_EMPTY)
+ {
+ disconnect_client(sender, "client num");
+ return;
+ };
+ int size = msgsizelookup(type);
+ assert(size!=-1);
+ loopi(size-2) getint(p);
+ break;
+ };
+
+ case SV_SENDMAP:
+ {
+ sgetstr();
+ int mapsize = getint(p);
+ sendmaps(sender, text, mapsize, p);
+ return;
+ }
+
+ case SV_RECVMAP:
+ send(sender, recvmap(sender));
+ return;
+
+ case SV_EXT: // allows for new features that require no server updates
+ {
+ for(int n = getint(p); n; n--) getint(p);
+ break;
+ };
+
+ default:
+ {
+ int size = msgsizelookup(type);
+ if(size==-1) { disconnect_client(sender, "tag type"); return; };
+ loopi(size-1) getint(p);
+ };
+ };
+
+ if(p>end) { disconnect_client(sender, "end of packet"); return; };
+ multicast(packet, sender);
+};
+
+void send_welcome(int n)
+{
+ ENetPacket * packet = enet_packet_create (NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, SV_INITS2C);
+ putint(p, n);
+ putint(p, PROTOCOL_VERSION);
+ putint(p, smapname[0]);
+ sendstring(serverpassword, p);
+ putint(p, clients.length()>maxclients);
+ if(smapname[0])
+ {
+ putint(p, SV_MAPCHANGE);
+ sendstring(smapname, p);
+ putint(p, mode);
+ putint(p, SV_ITEMLIST);
+ loopv(sents) if(sents[i].spawned) putint(p, i);
+ putint(p, -1);
+ };
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ send(n, packet);
+};
+
+void multicast(ENetPacket *packet, int sender)
+{
+ loopv(clients)
+ {
+ if(i==sender) continue;
+ send(i, packet);
+ };
+};
+
+void localclienttoserver(ENetPacket *packet)
+{
+ process(packet, 0);
+ if(!packet->referenceCount) enet_packet_destroy (packet);
+};
+
+client &addclient()
+{
+ loopv(clients) if(clients[i].type==ST_EMPTY) return clients[i];
+ return clients.add();
+};
+
+void checkintermission()
+{
+ if(!minremain)
+ {
+ interm = lastsec+10;
+ mapend = lastsec+1000;
+ };
+ send2(true, -1, SV_TIMEUP, minremain--);
+};
+
+void startintermission() { minremain = 0; checkintermission(); };
+
+void resetserverifempty()
+{
+ loopv(clients) if(clients[i].type!=ST_EMPTY) return;
+ clients.setsize(0);
+ smapname[0] = 0;
+ resetvotes();
+ resetitems();
+ mode = 0;
+ mapreload = false;
+ minremain = 10;
+ mapend = lastsec+minremain*60;
+ interm = 0;
+};
+
+int nonlocalclients = 0;
+int lastconnect = 0;
+
+void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in sp, or dedicated server loop
+{
+ loopv(sents) // spawn entities when timer reached
+ {
+ if(sents[i].spawnsecs && (sents[i].spawnsecs -= seconds-lastsec)<=0)
+ {
+ sents[i].spawnsecs = 0;
+ sents[i].spawned = true;
+ send2(true, -1, SV_ITEMSPAWN, i);
+ };
+ };
+
+ lastsec = seconds;
+
+ if((mode>1 || (mode==0 && nonlocalclients)) && seconds>mapend-minremain*60) checkintermission();
+ if(interm && seconds>interm)
+ {
+ interm = 0;
+ loopv(clients) if(clients[i].type!=ST_EMPTY)
+ {
+ send2(true, i, SV_MAPRELOAD, 0); // ask a client to trigger map reload
+ mapreload = true;
+ break;
+ };
+ };
+
+ resetserverifempty();
+
+ if(!isdedicated) return; // below is network only
+
+ int numplayers = 0;
+ loopv(clients) if(clients[i].type!=ST_EMPTY) ++numplayers;
+ serverms(mode, numplayers, minremain, smapname, seconds, clients.length()>=maxclients);
+
+ if(seconds-laststatus>60) // display bandwidth stats, useful for server ops
+ {
+ nonlocalclients = 0;
+ loopv(clients) if(clients[i].type==ST_TCPIP) nonlocalclients++;
+ laststatus = seconds;
+ if(nonlocalclients || bsend || brec) printf("status: %d remote clients, %.1f send, %.1f rec (K/sec)\n", nonlocalclients, bsend/60.0f/1024, brec/60.0f/1024);
+ bsend = brec = 0;
+ };
+
+ ENetEvent event;
+ if(enet_host_service(serverhost, &event, timeout) > 0)
+ {
+ switch(event.type)
+ {
+ case ENET_EVENT_TYPE_CONNECT:
+ {
+ client &c = addclient();
+ c.type = ST_TCPIP;
+ c.peer = event.peer;
+ c.peer->data = (void *)(&c-&clients[0]);
+ char hn[1024];
+ strcpy_s(c.hostname, (enet_address_get_host(&c.peer->address, hn, sizeof(hn))==0) ? hn : "localhost");
+ printf("client connected (%s)\n", c.hostname);
+ send_welcome(lastconnect = &c-&clients[0]);
+ break;
+ }
+ case ENET_EVENT_TYPE_RECEIVE:
+ brec += event.packet->dataLength;
+ process(event.packet, (int)event.peer->data);
+ if(event.packet->referenceCount==0) enet_packet_destroy(event.packet);
+ break;
+
+ case ENET_EVENT_TYPE_DISCONNECT:
+ if((int)event.peer->data<0) break;
+ printf("disconnected client (%s)\n", clients[(int)event.peer->data].hostname);
+ clients[(int)event.peer->data].type = ST_EMPTY;
+ send2(true, -1, SV_CDIS, (int)event.peer->data);
+ event.peer->data = (void *)-1;
+ break;
+ };
+
+ if(numplayers>maxclients)
+ {
+ disconnect_client(lastconnect, "maxclients reached");
+ };
+ };
+ #ifndef _WIN32
+ fflush(stdout);
+ #endif
+};
+
+void cleanupserver()
+{
+ if(serverhost) enet_host_destroy(serverhost);
+};
+
+void localdisconnect()
+{
+ loopv(clients) if(clients[i].type==ST_LOCAL) clients[i].type = ST_EMPTY;
+};
+
+void localconnect()
+{
+ client &c = addclient();
+ c.type = ST_LOCAL;
+ strcpy_s(c.hostname, "local");
+ send_welcome(&c-&clients[0]);
+};
+
+void initserver(bool dedicated, int uprate, char *sdesc, char *ip, char *master, char *passwd, int maxcl)
+{
+ serverpassword = passwd;
+ maxclients = maxcl;
+ servermsinit(master ? master : "wouter.fov120.com/cube/masterserver/", sdesc, dedicated);
+
+ if(isdedicated = dedicated)
+ {
+ ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
+ if(*ip && enet_address_set_host(&address, ip)<0) printf("WARNING: server ip not resolved");
+ serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate);
+ if(!serverhost) fatal("could not create server host\n");
+ loopi(MAXCLIENTS) serverhost->peers[i].data = (void *)-1;
+ };
+
+ resetserverifempty();
+
+ if(isdedicated) // do not return, this becomes main loop
+ {
+ #ifdef _WIN32
+ SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+ #endif
+ printf("dedicated server started, waiting for clients...\nCtrl-C to exit\n\n");
+ atexit(cleanupserver);
+ atexit(enet_deinitialize);
+ for(;;) serverslice(/*enet_time_get_sec()*/time(NULL), 5);
+ };
+};
DELETED src/serverbrowser.cpp
Index: src/serverbrowser.cpp
==================================================================
--- src/serverbrowser.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-// serverbrowser.cpp: eihrul's concurrent resolver, and server browser window management
-
-#include "cube.h"
-#include "SDL_thread.h"
-
-struct resolverthread
-{
- SDL_Thread *thread;
- char *query;
- int starttime;
-};
-
-struct resolverresult
-{
- char *query;
- ENetAddress address;
-};
-
-vector resolverthreads;
-vector resolverqueries;
-vector resolverresults;
-SDL_mutex *resolvermutex;
-SDL_sem *resolversem;
-int resolverlimit = 1000;
-
-int resolverloop(void * data)
-{
- resolverthread *rt = (resolverthread *)data;
- for(;;)
- {
- SDL_SemWait(resolversem);
- SDL_LockMutex(resolvermutex);
- if(resolverqueries.empty())
- {
- SDL_UnlockMutex(resolvermutex);
- continue;
- }
- rt->query = resolverqueries.pop();
- rt->starttime = lastmillis;
- SDL_UnlockMutex(resolvermutex);
- ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
- enet_address_set_host(&address, rt->query);
- SDL_LockMutex(resolvermutex);
- resolverresult &rr = resolverresults.add();
- rr.query = rt->query;
- rr.address = address;
- rt->query = NULL;
- rt->starttime = 0;
- SDL_UnlockMutex(resolvermutex);
- };
- return 0;
-};
-
-void resolverinit(int threads, int limit)
-{
- resolverlimit = limit;
- resolversem = SDL_CreateSemaphore(0);
- resolvermutex = SDL_CreateMutex();
-
- while(threads > 0)
- {
- resolverthread &rt = resolverthreads.add();
- rt.query = NULL;
- rt.starttime = 0;
- rt.thread = SDL_CreateThread(resolverloop, &rt);
- --threads;
- };
-};
-
-void resolverstop(resolverthread &rt, bool restart)
-{
- SDL_LockMutex(resolvermutex);
- SDL_KillThread(rt.thread);
- rt.query = NULL;
- rt.starttime = 0;
- rt.thread = NULL;
- if(restart) rt.thread = SDL_CreateThread(resolverloop, &rt);
- SDL_UnlockMutex(resolvermutex);
-};
-
-void resolverclear()
-{
- SDL_LockMutex(resolvermutex);
- resolverqueries.setsize(0);
- resolverresults.setsize(0);
- while (SDL_SemTryWait(resolversem) == 0);
- loopv(resolverthreads)
- {
- resolverthread &rt = resolverthreads[i];
- resolverstop(rt, true);
- };
- SDL_UnlockMutex(resolvermutex);
-};
-
-void resolverquery(char *name)
-{
- SDL_LockMutex(resolvermutex);
- resolverqueries.add(name);
- SDL_SemPost(resolversem);
- SDL_UnlockMutex(resolvermutex);
-};
-
-bool resolvercheck(char **name, ENetAddress *address)
-{
- SDL_LockMutex(resolvermutex);
- if(!resolverresults.empty())
- {
- resolverresult &rr = resolverresults.pop();
- *name = rr.query;
- *address = rr.address;
- SDL_UnlockMutex(resolvermutex);
- return true;
- }
- loopv(resolverthreads)
- {
- resolverthread &rt = resolverthreads[i];
- if(rt.query)
- {
- if(lastmillis - rt.starttime > resolverlimit)
- {
- resolverstop(rt, true);
- *name = rt.query;
- SDL_UnlockMutex(resolvermutex);
- return true;
- };
- };
- };
- SDL_UnlockMutex(resolvermutex);
- return false;
-};
-
-struct serverinfo
-{
- string name;
- string full;
- string map;
- string sdesc;
- int mode, numplayers, ping, protocol, minremain;
- ENetAddress address;
-};
-
-vector servers;
-ENetSocket pingsock = ENET_SOCKET_NULL;
-int lastinfo = 0;
-
-char *getservername(int n) { return servers[n].name; };
-
-void addserver(char *servername)
-{
- loopv(servers) if(strcmp(servers[i].name, servername)==0) return;
- serverinfo &si = servers.insert(0, serverinfo());
- strcpy_s(si.name, servername);
- si.full[0] = 0;
- si.mode = 0;
- si.numplayers = 0;
- si.ping = 9999;
- si.protocol = 0;
- si.minremain = 0;
- si.map[0] = 0;
- si.sdesc[0] = 0;
- si.address.host = ENET_HOST_ANY;
- si.address.port = CUBE_SERVINFO_PORT;
-};
-
-void pingservers()
-{
- ENetBuffer buf;
- uchar ping[MAXTRANS];
- uchar *p;
- loopv(servers)
- {
- serverinfo &si = servers[i];
- if(si.address.host == ENET_HOST_ANY) continue;
- p = ping;
- putint(p, lastmillis);
- buf.data = ping;
- buf.dataLength = p - ping;
- enet_socket_send(pingsock, &si.address, &buf, 1);
- };
- lastinfo = lastmillis;
-};
-
-void checkresolver()
-{
- char *name = NULL;
- ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
- while(resolvercheck(&name, &addr))
- {
- if(addr.host == ENET_HOST_ANY) continue;
- loopv(servers)
- {
- serverinfo &si = servers[i];
- if(name == si.name)
- {
- si.address = addr;
- addr.host = ENET_HOST_ANY;
- break;
- }
- }
- }
-}
-
-void checkpings()
-{
- enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
- ENetBuffer buf;
- ENetAddress addr;
- uchar ping[MAXTRANS], *p;
- char text[MAXTRANS];
- buf.data = ping;
- buf.dataLength = sizeof(ping);
- while(enet_socket_wait(pingsock, &events, 0) >= 0 && events)
- {
- if(enet_socket_receive(pingsock, &addr, &buf, 1) <= 0) return;
- loopv(servers)
- {
- serverinfo &si = servers[i];
- if(addr.host == si.address.host)
- {
- p = ping;
- si.ping = lastmillis - getint(p);
- si.protocol = getint(p);
- if(si.protocol!=PROTOCOL_VERSION) si.ping = 9998;
- si.mode = getint(p);
- si.numplayers = getint(p);
- si.minremain = getint(p);
- sgetstr();
- strcpy_s(si.map, text);
- sgetstr();
- strcpy_s(si.sdesc, text);
- break;
- };
- };
- };
-};
-
-int sicompare(const serverinfo *a, const serverinfo *b)
-{
- return a->ping>b->ping ? 1 : (a->pingping ? -1 : strcmp(a->name, b->name));
-};
-
-void refreshservers()
-{
- checkresolver();
- checkpings();
- if(lastmillis - lastinfo >= 5000) pingservers();
- servers.sort((void *)sicompare);
- int maxmenu = 16;
- loopv(servers)
- {
- serverinfo &si = servers[i];
- if(si.address.host != ENET_HOST_ANY && si.ping != 9999)
- {
- if(si.protocol!=PROTOCOL_VERSION) sprintf_s(si.full)("%s [different cube protocol]", si.name);
- else sprintf_s(si.full)("%d\t%d\t%s, %s: %s %s", si.ping, si.numplayers, si.map[0] ? si.map : "[unknown]", modestr(si.mode), si.name, si.sdesc);
- }
- else
- {
- sprintf_s(si.full)(si.address.host != ENET_HOST_ANY ? "%s [waiting for server response]" : "%s [unknown host]\t", si.name);
- }
- si.full[50] = 0; // cut off too long server descriptions
- menumanual(1, i, si.full);
- if(!--maxmenu) return;
- };
-};
-
-void servermenu()
-{
- if(pingsock == ENET_SOCKET_NULL)
- {
- pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL);
- resolverinit(1, 1000);
- };
- resolverclear();
- loopv(servers) resolverquery(servers[i].name);
- refreshservers();
- menuset(1);
-};
-
-void updatefrommaster()
-{
- const int MAXUPD = 32000;
- uchar buf[MAXUPD];
- uchar *reply = retrieveservers(buf, MAXUPD);
- if(!*reply || strstr((char *)reply, "") || strstr((char *)reply, "")) conoutf("master server not replying");
- else { servers.setsize(0); execute((char *)reply); };
- servermenu();
-};
-
-COMMAND(addserver, ARG_1STR);
-COMMAND(servermenu, ARG_NONE);
-COMMAND(updatefrommaster, ARG_NONE);
-
-void writeservercfg()
-{
- FILE *f = fopen("servers.cfg", "w");
- if(!f) return;
- fprintf(f, "// servers connected to are added here automatically\n\n");
- loopvrev(servers) fprintf(f, "addserver %s\n", servers[i].name);
- fclose(f);
-};
-
-
ADDED src/serverbrowser.cxx
Index: src/serverbrowser.cxx
==================================================================
--- /dev/null
+++ src/serverbrowser.cxx
@@ -0,0 +1,303 @@
+// serverbrowser.cpp: eihrul's concurrent resolver, and server browser window management
+
+#include "cube.h"
+#include "SDL_thread.h"
+
+struct resolverthread
+{
+ SDL_Thread *thread;
+ char *query;
+ int starttime;
+};
+
+struct resolverresult
+{
+ char *query;
+ ENetAddress address;
+};
+
+vector resolverthreads;
+vector resolverqueries;
+vector resolverresults;
+SDL_mutex *resolvermutex;
+SDL_sem *resolversem;
+int resolverlimit = 1000;
+
+int resolverloop(void * data)
+{
+ resolverthread *rt = (resolverthread *)data;
+ for(;;)
+ {
+ SDL_SemWait(resolversem);
+ SDL_LockMutex(resolvermutex);
+ if(resolverqueries.empty())
+ {
+ SDL_UnlockMutex(resolvermutex);
+ continue;
+ }
+ rt->query = resolverqueries.pop();
+ rt->starttime = lastmillis;
+ SDL_UnlockMutex(resolvermutex);
+ ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
+ enet_address_set_host(&address, rt->query);
+ SDL_LockMutex(resolvermutex);
+ resolverresult &rr = resolverresults.add();
+ rr.query = rt->query;
+ rr.address = address;
+ rt->query = NULL;
+ rt->starttime = 0;
+ SDL_UnlockMutex(resolvermutex);
+ };
+ return 0;
+};
+
+void resolverinit(int threads, int limit)
+{
+ resolverlimit = limit;
+ resolversem = SDL_CreateSemaphore(0);
+ resolvermutex = SDL_CreateMutex();
+
+ while(threads > 0)
+ {
+ resolverthread &rt = resolverthreads.add();
+ rt.query = NULL;
+ rt.starttime = 0;
+ rt.thread = SDL_CreateThread(resolverloop, &rt);
+ --threads;
+ };
+};
+
+void resolverstop(resolverthread &rt, bool restart)
+{
+ SDL_LockMutex(resolvermutex);
+ SDL_KillThread(rt.thread);
+ rt.query = NULL;
+ rt.starttime = 0;
+ rt.thread = NULL;
+ if(restart) rt.thread = SDL_CreateThread(resolverloop, &rt);
+ SDL_UnlockMutex(resolvermutex);
+};
+
+void resolverclear()
+{
+ SDL_LockMutex(resolvermutex);
+ resolverqueries.setsize(0);
+ resolverresults.setsize(0);
+ while (SDL_SemTryWait(resolversem) == 0);
+ loopv(resolverthreads)
+ {
+ resolverthread &rt = resolverthreads[i];
+ resolverstop(rt, true);
+ };
+ SDL_UnlockMutex(resolvermutex);
+};
+
+void resolverquery(char *name)
+{
+ SDL_LockMutex(resolvermutex);
+ resolverqueries.add(name);
+ SDL_SemPost(resolversem);
+ SDL_UnlockMutex(resolvermutex);
+};
+
+bool resolvercheck(char **name, ENetAddress *address)
+{
+ SDL_LockMutex(resolvermutex);
+ if(!resolverresults.empty())
+ {
+ resolverresult &rr = resolverresults.pop();
+ *name = rr.query;
+ *address = rr.address;
+ SDL_UnlockMutex(resolvermutex);
+ return true;
+ }
+ loopv(resolverthreads)
+ {
+ resolverthread &rt = resolverthreads[i];
+ if(rt.query)
+ {
+ if(lastmillis - rt.starttime > resolverlimit)
+ {
+ resolverstop(rt, true);
+ *name = rt.query;
+ SDL_UnlockMutex(resolvermutex);
+ return true;
+ };
+ };
+ };
+ SDL_UnlockMutex(resolvermutex);
+ return false;
+};
+
+struct serverinfo
+{
+ string name;
+ string full;
+ string map;
+ string sdesc;
+ int mode, numplayers, ping, protocol, minremain;
+ ENetAddress address;
+};
+
+vector servers;
+ENetSocket pingsock = ENET_SOCKET_NULL;
+int lastinfo = 0;
+
+char *getservername(int n) { return servers[n].name; };
+
+void addserver(char *servername)
+{
+ loopv(servers) if(strcmp(servers[i].name, servername)==0) return;
+ serverinfo &si = servers.insert(0, serverinfo());
+ strcpy_s(si.name, servername);
+ si.full[0] = 0;
+ si.mode = 0;
+ si.numplayers = 0;
+ si.ping = 9999;
+ si.protocol = 0;
+ si.minremain = 0;
+ si.map[0] = 0;
+ si.sdesc[0] = 0;
+ si.address.host = ENET_HOST_ANY;
+ si.address.port = CUBE_SERVINFO_PORT;
+};
+
+void pingservers()
+{
+ ENetBuffer buf;
+ uchar ping[MAXTRANS];
+ uchar *p;
+ loopv(servers)
+ {
+ serverinfo &si = servers[i];
+ if(si.address.host == ENET_HOST_ANY) continue;
+ p = ping;
+ putint(p, lastmillis);
+ buf.data = ping;
+ buf.dataLength = p - ping;
+ enet_socket_send(pingsock, &si.address, &buf, 1);
+ };
+ lastinfo = lastmillis;
+};
+
+void checkresolver()
+{
+ char *name = NULL;
+ ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
+ while(resolvercheck(&name, &addr))
+ {
+ if(addr.host == ENET_HOST_ANY) continue;
+ loopv(servers)
+ {
+ serverinfo &si = servers[i];
+ if(name == si.name)
+ {
+ si.address = addr;
+ addr.host = ENET_HOST_ANY;
+ break;
+ }
+ }
+ }
+}
+
+void checkpings()
+{
+ enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
+ ENetBuffer buf;
+ ENetAddress addr;
+ uchar ping[MAXTRANS], *p;
+ char text[MAXTRANS];
+ buf.data = ping;
+ buf.dataLength = sizeof(ping);
+ while(enet_socket_wait(pingsock, &events, 0) >= 0 && events)
+ {
+ if(enet_socket_receive(pingsock, &addr, &buf, 1) <= 0) return;
+ loopv(servers)
+ {
+ serverinfo &si = servers[i];
+ if(addr.host == si.address.host)
+ {
+ p = ping;
+ si.ping = lastmillis - getint(p);
+ si.protocol = getint(p);
+ if(si.protocol!=PROTOCOL_VERSION) si.ping = 9998;
+ si.mode = getint(p);
+ si.numplayers = getint(p);
+ si.minremain = getint(p);
+ sgetstr();
+ strcpy_s(si.map, text);
+ sgetstr();
+ strcpy_s(si.sdesc, text);
+ break;
+ };
+ };
+ };
+};
+
+int sicompare(const serverinfo *a, const serverinfo *b)
+{
+ return a->ping>b->ping ? 1 : (a->pingping ? -1 : strcmp(a->name, b->name));
+};
+
+void refreshservers()
+{
+ checkresolver();
+ checkpings();
+ if(lastmillis - lastinfo >= 5000) pingservers();
+ servers.sort((void *)sicompare);
+ int maxmenu = 16;
+ loopv(servers)
+ {
+ serverinfo &si = servers[i];
+ if(si.address.host != ENET_HOST_ANY && si.ping != 9999)
+ {
+ if(si.protocol!=PROTOCOL_VERSION) sprintf_s(si.full)("%s [different cube protocol]", si.name);
+ else sprintf_s(si.full)("%d\t%d\t%s, %s: %s %s", si.ping, si.numplayers, si.map[0] ? si.map : "[unknown]", modestr(si.mode), si.name, si.sdesc);
+ }
+ else
+ {
+ sprintf_s(si.full)(si.address.host != ENET_HOST_ANY ? "%s [waiting for server response]" : "%s [unknown host]\t", si.name);
+ }
+ si.full[50] = 0; // cut off too long server descriptions
+ menumanual(1, i, si.full);
+ if(!--maxmenu) return;
+ };
+};
+
+void servermenu()
+{
+ if(pingsock == ENET_SOCKET_NULL)
+ {
+ pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL);
+ resolverinit(1, 1000);
+ };
+ resolverclear();
+ loopv(servers) resolverquery(servers[i].name);
+ refreshservers();
+ menuset(1);
+};
+
+void updatefrommaster()
+{
+ const int MAXUPD = 32000;
+ uchar buf[MAXUPD];
+ uchar *reply = retrieveservers(buf, MAXUPD);
+ if(!*reply || strstr((char *)reply, "") || strstr((char *)reply, "")) conoutf("master server not replying");
+ else { servers.setsize(0); execute((char *)reply); };
+ servermenu();
+};
+
+COMMAND(addserver, ARG_1STR);
+COMMAND(servermenu, ARG_NONE);
+COMMAND(updatefrommaster, ARG_NONE);
+
+void writeservercfg()
+{
+ FILE *f = fopen("servers.cfg", "w");
+ if(!f) return;
+ fprintf(f, "// servers connected to are added here automatically\n\n");
+ loopvrev(servers) fprintf(f, "addserver %s\n", servers[i].name);
+ fclose(f);
+};
+
+
DELETED src/serverms.cpp
Index: src/serverms.cpp
==================================================================
--- src/serverms.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-// all server side masterserver and pinging functionality
-
-#include "cube.h"
-
-ENetSocket mssock = ENET_SOCKET_NULL;
-
-void httpgetsend(ENetAddress &ad, char *hostname, char *req, char *ref, char *agent)
-{
- if(ad.host==ENET_HOST_ANY)
- {
- printf("looking up %s...\n", hostname);
- enet_address_set_host(&ad, hostname);
- if(ad.host==ENET_HOST_ANY) return;
- };
- if(mssock!=ENET_SOCKET_NULL) enet_socket_destroy(mssock);
- mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL);
- if(mssock==ENET_SOCKET_NULL) { printf("could not open socket\n"); return; };
- if(enet_socket_connect(mssock, &ad)<0) { printf("could not connect\n"); return; };
- ENetBuffer buf;
- sprintf_sd(httpget)("GET %s HTTP/1.0\nHost: %s\nReferer: %s\nUser-Agent: %s\n\n", req, hostname, ref, agent);
- buf.data = httpget;
- buf.dataLength = strlen((char *)buf.data);
- printf("sending request to %s...\n", hostname);
- enet_socket_send(mssock, NULL, &buf, 1);
-};
-
-void httpgetrecieve(ENetBuffer &buf)
-{
- if(mssock==ENET_SOCKET_NULL) return;
- enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
- if(enet_socket_wait(mssock, &events, 0) >= 0 && events)
- {
- int len = enet_socket_receive(mssock, NULL, &buf, 1);
- if(len<=0)
- {
- enet_socket_destroy(mssock);
- mssock = ENET_SOCKET_NULL;
- return;
- };
- buf.data = ((char *)buf.data)+len;
- ((char*)buf.data)[0] = 0;
- buf.dataLength -= len;
- };
-};
-
-uchar *stripheader(uchar *b)
-{
- char *s = strstr((char *)b, "\n\r\n");
- if(!s) s = strstr((char *)b, "\n\n");
- return s ? (uchar *)s : b;
-};
-
-ENetAddress masterserver = { ENET_HOST_ANY, 80 };
-int updmaster = 0;
-string masterbase;
-string masterpath;
-uchar masterrep[MAXTRANS];
-ENetBuffer masterb;
-
-void updatemasterserver(int seconds)
-{
- if(seconds>updmaster) // send alive signal to masterserver every hour of uptime
- {
- sprintf_sd(path)("%sregister.do?action=add", masterpath);
- httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server");
- masterrep[0] = 0;
- masterb.data = masterrep;
- masterb.dataLength = MAXTRANS-1;
- updmaster = seconds+60*60;
- };
-};
-
-void checkmasterreply()
-{
- bool busy = mssock!=ENET_SOCKET_NULL;
- httpgetrecieve(masterb);
- if(busy && mssock==ENET_SOCKET_NULL) printf("masterserver reply: %s\n", stripheader(masterrep));
-};
-
-uchar *retrieveservers(uchar *buf, int buflen)
-{
- sprintf_sd(path)("%sretrieve.do?item=list", masterpath);
- httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server");
- ENetBuffer eb;
- buf[0] = 0;
- eb.data = buf;
- eb.dataLength = buflen-1;
- while(mssock!=ENET_SOCKET_NULL) httpgetrecieve(eb);
- return stripheader(buf);
-};
-
-ENetSocket pongsock = ENET_SOCKET_NULL;
-string serverdesc;
-
-void serverms(int mode, int numplayers, int minremain, char *smapname, int seconds, bool isfull)
-{
- checkmasterreply();
- updatemasterserver(seconds);
-
- // reply all server info requests
- ENetBuffer buf;
- ENetAddress addr;
- uchar pong[MAXTRANS], *p;
- int len;
- enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
- buf.data = pong;
- while(enet_socket_wait(pongsock, &events, 0) >= 0 && events)
- {
- buf.dataLength = sizeof(pong);
- len = enet_socket_receive(pongsock, &addr, &buf, 1);
- if(len < 0) return;
- p = &pong[len];
- putint(p, PROTOCOL_VERSION);
- putint(p, mode);
- putint(p, numplayers);
- putint(p, minremain);
- string mname;
- strcpy_s(mname, isfull ? "[FULL] " : "");
- strcat_s(mname, smapname);
- sendstring(mname, p);
- sendstring(serverdesc, p);
- buf.dataLength = p - pong;
- enet_socket_send(pongsock, &addr, &buf, 1);
- };
-};
-
-void servermsinit(const char *master, char *sdesc, bool listen)
-{
- const char *mid = strstr(master, "/");
- if(!mid) mid = master;
- strcpy_s(masterpath, mid);
- strn0cpy(masterbase, master, mid-master+1);
- strcpy_s(serverdesc, sdesc);
-
- if(listen)
- {
- ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
- pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address);
- if(pongsock == ENET_SOCKET_NULL) fatal("could not create server info socket\n");
- };
-};
ADDED src/serverms.cxx
Index: src/serverms.cxx
==================================================================
--- /dev/null
+++ src/serverms.cxx
@@ -0,0 +1,141 @@
+// all server side masterserver and pinging functionality
+
+#include "cube.h"
+
+ENetSocket mssock = ENET_SOCKET_NULL;
+
+void httpgetsend(ENetAddress &ad, char *hostname, char *req, char *ref, char *agent)
+{
+ if(ad.host==ENET_HOST_ANY)
+ {
+ printf("looking up %s...\n", hostname);
+ enet_address_set_host(&ad, hostname);
+ if(ad.host==ENET_HOST_ANY) return;
+ };
+ if(mssock!=ENET_SOCKET_NULL) enet_socket_destroy(mssock);
+ mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL);
+ if(mssock==ENET_SOCKET_NULL) { printf("could not open socket\n"); return; };
+ if(enet_socket_connect(mssock, &ad)<0) { printf("could not connect\n"); return; };
+ ENetBuffer buf;
+ sprintf_sd(httpget)("GET %s HTTP/1.0\nHost: %s\nReferer: %s\nUser-Agent: %s\n\n", req, hostname, ref, agent);
+ buf.data = httpget;
+ buf.dataLength = strlen((char *)buf.data);
+ printf("sending request to %s...\n", hostname);
+ enet_socket_send(mssock, NULL, &buf, 1);
+};
+
+void httpgetrecieve(ENetBuffer &buf)
+{
+ if(mssock==ENET_SOCKET_NULL) return;
+ enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
+ if(enet_socket_wait(mssock, &events, 0) >= 0 && events)
+ {
+ int len = enet_socket_receive(mssock, NULL, &buf, 1);
+ if(len<=0)
+ {
+ enet_socket_destroy(mssock);
+ mssock = ENET_SOCKET_NULL;
+ return;
+ };
+ buf.data = ((char *)buf.data)+len;
+ ((char*)buf.data)[0] = 0;
+ buf.dataLength -= len;
+ };
+};
+
+uchar *stripheader(uchar *b)
+{
+ char *s = strstr((char *)b, "\n\r\n");
+ if(!s) s = strstr((char *)b, "\n\n");
+ return s ? (uchar *)s : b;
+};
+
+ENetAddress masterserver = { ENET_HOST_ANY, 80 };
+int updmaster = 0;
+string masterbase;
+string masterpath;
+uchar masterrep[MAXTRANS];
+ENetBuffer masterb;
+
+void updatemasterserver(int seconds)
+{
+ if(seconds>updmaster) // send alive signal to masterserver every hour of uptime
+ {
+ sprintf_sd(path)("%sregister.do?action=add", masterpath);
+ httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server");
+ masterrep[0] = 0;
+ masterb.data = masterrep;
+ masterb.dataLength = MAXTRANS-1;
+ updmaster = seconds+60*60;
+ };
+};
+
+void checkmasterreply()
+{
+ bool busy = mssock!=ENET_SOCKET_NULL;
+ httpgetrecieve(masterb);
+ if(busy && mssock==ENET_SOCKET_NULL) printf("masterserver reply: %s\n", stripheader(masterrep));
+};
+
+uchar *retrieveservers(uchar *buf, int buflen)
+{
+ sprintf_sd(path)("%sretrieve.do?item=list", masterpath);
+ httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server");
+ ENetBuffer eb;
+ buf[0] = 0;
+ eb.data = buf;
+ eb.dataLength = buflen-1;
+ while(mssock!=ENET_SOCKET_NULL) httpgetrecieve(eb);
+ return stripheader(buf);
+};
+
+ENetSocket pongsock = ENET_SOCKET_NULL;
+string serverdesc;
+
+void serverms(int mode, int numplayers, int minremain, char *smapname, int seconds, bool isfull)
+{
+ checkmasterreply();
+ updatemasterserver(seconds);
+
+ // reply all server info requests
+ ENetBuffer buf;
+ ENetAddress addr;
+ uchar pong[MAXTRANS], *p;
+ int len;
+ enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
+ buf.data = pong;
+ while(enet_socket_wait(pongsock, &events, 0) >= 0 && events)
+ {
+ buf.dataLength = sizeof(pong);
+ len = enet_socket_receive(pongsock, &addr, &buf, 1);
+ if(len < 0) return;
+ p = &pong[len];
+ putint(p, PROTOCOL_VERSION);
+ putint(p, mode);
+ putint(p, numplayers);
+ putint(p, minremain);
+ string mname;
+ strcpy_s(mname, isfull ? "[FULL] " : "");
+ strcat_s(mname, smapname);
+ sendstring(mname, p);
+ sendstring(serverdesc, p);
+ buf.dataLength = p - pong;
+ enet_socket_send(pongsock, &addr, &buf, 1);
+ };
+};
+
+void servermsinit(const char *master, char *sdesc, bool listen)
+{
+ const char *mid = strstr(master, "/");
+ if(!mid) mid = master;
+ strcpy_s(masterpath, mid);
+ strn0cpy(masterbase, master, mid-master+1);
+ strcpy_s(serverdesc, sdesc);
+
+ if(listen)
+ {
+ ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
+ pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address);
+ if(pongsock == ENET_SOCKET_NULL) fatal("could not create server info socket\n");
+ };
+};
DELETED src/serverutil.cpp
Index: src/serverutil.cpp
==================================================================
--- src/serverutil.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-// misc useful functions used by the server
-
-#include "cube.h"
-
-// all network traffic is in 32bit ints, which are then compressed using the following simple scheme (assumes that most values are small).
-
-void putint(uchar *&p, int n)
-{
- if(n<128 && n>-127) { *p++ = n; }
- else if(n<0x8000 && n>=-0x8000) { *p++ = 0x80; *p++ = n; *p++ = n>>8; }
- else { *p++ = 0x81; *p++ = n; *p++ = n>>8; *p++ = n>>16; *p++ = n>>24; };
-};
-
-int getint(uchar *&p)
-{
- int c = *((char *)p);
- p++;
- if(c==-128) { int n = *p++; n |= *((char *)p)<<8; p++; return n;}
- else if(c==-127) { int n = *p++; n |= *p++<<8; n |= *p++<<16; return n|(*p++<<24); }
- else return c;
-};
-
-void sendstring(char *t, uchar *&p)
-{
- while(*t) putint(p, *t++);
- putint(p, 0);
-};
-
-const char *modenames[] =
-{
- "SP", "DMSP", "ffa/default", "coopedit", "ffa/duel", "teamplay",
- "instagib", "instagib team", "efficiency", "efficiency team",
- "insta arena", "insta clan arena", "tactics arena", "tactics clan arena",
-};
-
-const char *modestr(int n) { return (n>=-2 && n<12) ? modenames[n+2] : "unknown"; };
-
-char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes
-{
- SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2,
- SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6,
- SV_DIED, 2, SV_DAMAGE, 4, SV_SHOT, 8, SV_FRAGS, 2,
- SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2,
- SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2,
- SV_TIMEUP, 2, SV_EDITENT, 10, SV_MAPRELOAD, 2, SV_ITEMACC, 2,
- SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0,
- SV_EXT, 0,
- -1
-};
-
-char msgsizelookup(int msg)
-{
- for(char *p = msgsizesl; *p>=0; p += 2) if(*p==msg) return p[1];
- return -1;
-};
-
-// sending of maps between clients
-
-string copyname;
-int copysize;
-uchar *copydata = NULL;
-
-void sendmaps(int n, string mapname, int mapsize, uchar *mapdata)
-{
- if(mapsize <= 0 || mapsize > 256*256) return;
- strcpy_s(copyname, mapname);
- copysize = mapsize;
- if(copydata) free(copydata);
- copydata = (uchar *)alloc(mapsize);
- memcpy(copydata, mapdata, mapsize);
-}
-
-ENetPacket *recvmap(int n)
-{
- if(!copydata) return NULL;
- ENetPacket *packet = enet_packet_create(NULL, MAXTRANS + copysize, ENET_PACKET_FLAG_RELIABLE);
- uchar *start = packet->data;
- uchar *p = start+2;
- putint(p, SV_RECVMAP);
- sendstring(copyname, p);
- putint(p, copysize);
- memcpy(p, copydata, copysize);
- p += copysize;
- *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
- enet_packet_resize(packet, p-start);
- return packet;
-}
-
-
-#ifdef STANDALONE
-
-void localservertoclient(uchar *buf, int len) {};
-void fatal(char *s, char *o) { cleanupserver(); printf("servererror: %s\n", s); exit(1); };
-void *alloc(int s) { void *b = calloc(1,s); if(!b) fatal("no memory!"); return b; };
-
-int main(int argc, char* argv[])
-{
- int uprate = 0, maxcl = 4;
- char *sdesc = "", *ip = "", *master = NULL, *passwd = "";
-
- for(int i = 1; i-127) { *p++ = n; }
+ else if(n<0x8000 && n>=-0x8000) { *p++ = 0x80; *p++ = n; *p++ = n>>8; }
+ else { *p++ = 0x81; *p++ = n; *p++ = n>>8; *p++ = n>>16; *p++ = n>>24; };
+};
+
+int getint(uchar *&p)
+{
+ int c = *((char *)p);
+ p++;
+ if(c==-128) { int n = *p++; n |= *((char *)p)<<8; p++; return n;}
+ else if(c==-127) { int n = *p++; n |= *p++<<8; n |= *p++<<16; return n|(*p++<<24); }
+ else return c;
+};
+
+void sendstring(char *t, uchar *&p)
+{
+ while(*t) putint(p, *t++);
+ putint(p, 0);
+};
+
+const char *modenames[] =
+{
+ "SP", "DMSP", "ffa/default", "coopedit", "ffa/duel", "teamplay",
+ "instagib", "instagib team", "efficiency", "efficiency team",
+ "insta arena", "insta clan arena", "tactics arena", "tactics clan arena",
+};
+
+const char *modestr(int n) { return (n>=-2 && n<12) ? modenames[n+2] : "unknown"; };
+
+char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes
+{
+ SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2,
+ SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6,
+ SV_DIED, 2, SV_DAMAGE, 4, SV_SHOT, 8, SV_FRAGS, 2,
+ SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2,
+ SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2,
+ SV_TIMEUP, 2, SV_EDITENT, 10, SV_MAPRELOAD, 2, SV_ITEMACC, 2,
+ SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0,
+ SV_EXT, 0,
+ -1
+};
+
+char msgsizelookup(int msg)
+{
+ for(char *p = msgsizesl; *p>=0; p += 2) if(*p==msg) return p[1];
+ return -1;
+};
+
+// sending of maps between clients
+
+string copyname;
+int copysize;
+uchar *copydata = NULL;
+
+void sendmaps(int n, string mapname, int mapsize, uchar *mapdata)
+{
+ if(mapsize <= 0 || mapsize > 256*256) return;
+ strcpy_s(copyname, mapname);
+ copysize = mapsize;
+ if(copydata) free(copydata);
+ copydata = (uchar *)alloc(mapsize);
+ memcpy(copydata, mapdata, mapsize);
+}
+
+ENetPacket *recvmap(int n)
+{
+ if(!copydata) return NULL;
+ ENetPacket *packet = enet_packet_create(NULL, MAXTRANS + copysize, ENET_PACKET_FLAG_RELIABLE);
+ uchar *start = packet->data;
+ uchar *p = start+2;
+ putint(p, SV_RECVMAP);
+ sendstring(copyname, p);
+ putint(p, copysize);
+ memcpy(p, copydata, copysize);
+ p += copysize;
+ *(ushort *)start = ENET_HOST_TO_NET_16(p-start);
+ enet_packet_resize(packet, p-start);
+ return packet;
+}
+
+
+#ifdef STANDALONE
+
+void localservertoclient(uchar *buf, int len) {};
+void fatal(char *s, char *o) { cleanupserver(); printf("servererror: %s\n", s); exit(1); };
+void *alloc(int s) { void *b = calloc(1,s); if(!b) fatal("no memory!"); return b; };
+
+int main(int argc, char* argv[])
+{
+ int uprate = 0, maxcl = 4;
+ char *sdesc = "", *ip = "", *master = NULL, *passwd = "";
+
+ for(int i = 1; i=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); };
- }
- else
- {
- conoutf("could not play music: %s", sn);
- };
- #endif
- };
-};
-
-COMMAND(music, ARG_1STR);
-
-#ifdef USE_MIXER
-vector samples;
-#else
-vector samples;
-#endif
-
-cvector snames;
-
-int registersound(char *name)
-{
- loopv(snames) if(strcmp(snames[i], name)==0) return i;
- snames.add(newstring(name));
- samples.add(NULL);
- return samples.length()-1;
-};
-
-COMMAND(registersound, ARG_1EST);
-
-void cleansound()
-{
- if(nosound) return;
- stopsound();
- #ifdef USE_MIXER
- Mix_CloseAudio();
- #else
- FSOUND_Close();
- #endif
-};
-
-VAR(stereo, 0, 1, 1);
-
-void updatechanvol(int chan, vec *loc)
-{
- int vol = soundvol, pan = 255/2;
- if(loc)
- {
- vdist(dist, v, *loc, player1->o);
- vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation
- if(stereo && (v.x != 0 || v.y != 0))
- {
- float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis
- pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right)
- };
- };
- vol = (vol*MAXVOL)/255;
- #ifdef USE_MIXER
- Mix_Volume(chan, vol);
- Mix_SetPanning(chan, 255-pan, pan);
- #else
- FSOUND_SetVolume(chan, vol);
- FSOUND_SetPan(chan, pan);
- #endif
-};
-
-void newsoundloc(int chan, vec *loc)
-{
- assert(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp
- if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; };
-
- if(!samples[n])
- {
- sprintf_sd(buf)("packages/sounds/%s.wav", snames[n]);
-
- #ifdef USE_MIXER
- samples[n] = Mix_LoadWAV(path(buf));
- #else
- samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0);
- #endif
-
- if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; };
- };
-
- #ifdef USE_MIXER
- int chan = Mix_PlayChannel(-1, samples[n], 0);
- #else
- int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true);
- #endif
- if(chan<0) return;
- if(loc) newsoundloc(chan, loc);
- updatechanvol(chan, loc);
- #ifndef USE_MIXER
- FSOUND_SetPaused(chan, false);
- #endif
-};
-
-void sound(int n) { playsound(n, NULL); };
-COMMAND(sound, ARG_1INT);
ADDED src/sound.cxx
Index: src/sound.cxx
==================================================================
--- /dev/null
+++ src/sound.cxx
@@ -0,0 +1,226 @@
+// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform)
+
+#include "cube.h"
+
+//#ifndef _WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback
+#define USE_MIXER
+//#endif
+
+VARP(soundvol, 0, 255, 255);
+VARP(musicvol, 0, 128, 255);
+bool nosound = false;
+
+#define MAXCHAN 32
+#define SOUNDFREQ 22050
+
+struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN];
+
+#ifdef USE_MIXER
+ #include "SDL_mixer.h"
+ #define MAXVOL MIX_MAX_VOLUME
+ Mix_Music *mod = NULL;
+ void *stream = NULL;
+#else
+ #include "fmod.h"
+ #define MAXVOL 255
+ FMUSIC_MODULE *mod = NULL;
+ FSOUND_STREAM *stream = NULL;
+#endif
+
+void stopsound()
+{
+ if(nosound) return;
+ if(mod)
+ {
+ #ifdef USE_MIXER
+ Mix_HaltMusic();
+ Mix_FreeMusic(mod);
+ #else
+ FMUSIC_FreeSong(mod);
+ #endif
+ mod = NULL;
+ };
+ if(stream)
+ {
+ #ifndef USE_MIXER
+ FSOUND_Stream_Close(stream);
+ #endif
+ stream = NULL;
+ };
+};
+
+VAR(soundbufferlen, 128, 1024, 4096);
+
+void initsound()
+{
+ memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN);
+ #ifdef USE_MIXER
+ if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0)
+ {
+ conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError());
+ nosound = true;
+ };
+ Mix_AllocateChannels(MAXCHAN);
+ #else
+ if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); };
+ }
+ else
+ {
+ conoutf("could not play music: %s", sn);
+ };
+ #endif
+ };
+};
+
+COMMAND(music, ARG_1STR);
+
+#ifdef USE_MIXER
+vector samples;
+#else
+vector samples;
+#endif
+
+cvector snames;
+
+int registersound(char *name)
+{
+ loopv(snames) if(strcmp(snames[i], name)==0) return i;
+ snames.add(newstring(name));
+ samples.add(NULL);
+ return samples.length()-1;
+};
+
+COMMAND(registersound, ARG_1EST);
+
+void cleansound()
+{
+ if(nosound) return;
+ stopsound();
+ #ifdef USE_MIXER
+ Mix_CloseAudio();
+ #else
+ FSOUND_Close();
+ #endif
+};
+
+VAR(stereo, 0, 1, 1);
+
+void updatechanvol(int chan, vec *loc)
+{
+ int vol = soundvol, pan = 255/2;
+ if(loc)
+ {
+ vdist(dist, v, *loc, player1->o);
+ vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation
+ if(stereo && (v.x != 0 || v.y != 0))
+ {
+ float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis
+ pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right)
+ };
+ };
+ vol = (vol*MAXVOL)/255;
+ #ifdef USE_MIXER
+ Mix_Volume(chan, vol);
+ Mix_SetPanning(chan, 255-pan, pan);
+ #else
+ FSOUND_SetVolume(chan, vol);
+ FSOUND_SetPan(chan, pan);
+ #endif
+};
+
+void newsoundloc(int chan, vec *loc)
+{
+ assert(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp
+ if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; };
+
+ if(!samples[n])
+ {
+ sprintf_sd(buf)("packages/sounds/%s.wav", snames[n]);
+
+ #ifdef USE_MIXER
+ samples[n] = Mix_LoadWAV(path(buf));
+ #else
+ samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0);
+ #endif
+
+ if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; };
+ };
+
+ #ifdef USE_MIXER
+ int chan = Mix_PlayChannel(-1, samples[n], 0);
+ #else
+ int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true);
+ #endif
+ if(chan<0) return;
+ if(loc) newsoundloc(chan, loc);
+ updatechanvol(chan, loc);
+ #ifndef USE_MIXER
+ FSOUND_SetPaused(chan, false);
+ #endif
+};
+
+void sound(int n) { playsound(n, NULL); };
+COMMAND(sound, ARG_1INT);
DELETED src/tools.cpp
Index: src/tools.cpp
==================================================================
--- src/tools.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-// implementation of generic tools
-
-#include "tools.h"
-#include
-
-//////////////////////////// pool ///////////////////////////
-
-pool::pool()
-{
- blocks = 0;
- allocnext(POOLSIZE);
- for(int i = 0; iMAXREUSESIZE)
- {
- return malloc(size);
- }
- else
- {
- size = bucket(size);
- void **r = (void **)reuse[size];
- if(r)
- {
- reuse[size] = *r;
- return (void *)r;
- }
- else
- {
- size <<= PTRBITS;
- if(leftMAXREUSESIZE)
- {
- free(p);
- }
- else
- {
- size = bucket(size);
- if(size) // only needed for 0-size free, are there any?
- {
- *((void **)p) = reuse[size];
- reuse[size] = p;
- };
- };
-};
-
-void *pool::realloc(void *p, size_t oldsize, size_t newsize)
-{
- void *np = alloc(newsize);
- if(!oldsize) return np;
- memcpy(np, p, newsize>oldsize ? oldsize : newsize);
- dealloc(p, oldsize);
- return np;
-};
-
-void pool::dealloc_block(void *b)
-{
- if(b)
- {
- dealloc_block(*((char **)b));
- free(b);
- };
-}
-
-void pool::allocnext(size_t allocsize)
-{
- char *b = (char *)malloc(allocsize+PTRSIZE);
- *((char **)b) = blocks;
- blocks = b;
- p = b+PTRSIZE;
- left = allocsize;
-};
-
-char *pool::string(char *s, size_t l)
-{
- char *b = (char *)alloc(l+1);
- strncpy(b,s,l);
- b[l] = 0;
- return b;
-};
-
-pool *gp() // useful for global buffers that need to be initialisation order independant
-{
- static pool *p = NULL;
- return p ? p : (p = new pool());
-};
-
-
-///////////////////////// misc tools ///////////////////////
-
-char *path(char *s)
-{
- for(char *t = s; t = strpbrk(t, "/\\"); *t++ = PATHDIV);
- return s;
-};
-
-char *loadfile(char *fn, int *size)
-{
- FILE *f = fopen(fn, "rb");
- if(!f) return NULL;
- fseek(f, 0, SEEK_END);
- int len = ftell(f);
- fseek(f, 0, SEEK_SET);
- char *buf = (char *)malloc(len+1);
- if(!buf) return NULL;
- buf[len] = 0;
- size_t rlen = fread(buf, 1, len, f);
- fclose(f);
- if(len!=rlen || len<=0)
- {
- free(buf);
- return NULL;
- };
- if(size!=NULL) *size = len;
- return buf;
-};
-
-void endianswap(void *memory, int stride, int length) // little indians as storage format
-{
- if(*((char *)&stride)) return;
- loop(w, length) loop(i, stride/2)
- {
- uchar *p = (uchar *)memory+w*stride;
- uchar t = p[i];
- p[i] = p[stride-i-1];
- p[stride-i-1] = t;
- };
-}
ADDED src/tools.cxx
Index: src/tools.cxx
==================================================================
--- /dev/null
+++ src/tools.cxx
@@ -0,0 +1,140 @@
+// implementation of generic tools
+
+#include "tools.h"
+#include
+
+//////////////////////////// pool ///////////////////////////
+
+pool::pool()
+{
+ blocks = 0;
+ allocnext(POOLSIZE);
+ for(int i = 0; iMAXREUSESIZE)
+ {
+ return malloc(size);
+ }
+ else
+ {
+ size = bucket(size);
+ void **r = (void **)reuse[size];
+ if(r)
+ {
+ reuse[size] = *r;
+ return (void *)r;
+ }
+ else
+ {
+ size <<= PTRBITS;
+ if(leftMAXREUSESIZE)
+ {
+ free(p);
+ }
+ else
+ {
+ size = bucket(size);
+ if(size) // only needed for 0-size free, are there any?
+ {
+ *((void **)p) = reuse[size];
+ reuse[size] = p;
+ };
+ };
+};
+
+void *pool::realloc(void *p, size_t oldsize, size_t newsize)
+{
+ void *np = alloc(newsize);
+ if(!oldsize) return np;
+ memcpy(np, p, newsize>oldsize ? oldsize : newsize);
+ dealloc(p, oldsize);
+ return np;
+};
+
+void pool::dealloc_block(void *b)
+{
+ if(b)
+ {
+ dealloc_block(*((char **)b));
+ free(b);
+ };
+}
+
+void pool::allocnext(size_t allocsize)
+{
+ char *b = (char *)malloc(allocsize+PTRSIZE);
+ *((char **)b) = blocks;
+ blocks = b;
+ p = b+PTRSIZE;
+ left = allocsize;
+};
+
+char *pool::string(char *s, size_t l)
+{
+ char *b = (char *)alloc(l+1);
+ strncpy(b,s,l);
+ b[l] = 0;
+ return b;
+};
+
+pool *gp() // useful for global buffers that need to be initialisation order independant
+{
+ static pool *p = NULL;
+ return p ? p : (p = new pool());
+};
+
+
+///////////////////////// misc tools ///////////////////////
+
+char *path(char *s)
+{
+ for(char *t = s; t = strpbrk(t, "/\\"); *t++ = PATHDIV);
+ return s;
+};
+
+char *loadfile(char *fn, int *size)
+{
+ FILE *f = fopen(fn, "rb");
+ if(!f) return NULL;
+ fseek(f, 0, SEEK_END);
+ int len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ char *buf = (char *)malloc(len+1);
+ if(!buf) return NULL;
+ buf[len] = 0;
+ size_t rlen = fread(buf, 1, len, f);
+ fclose(f);
+ if(len!=rlen || len<=0)
+ {
+ free(buf);
+ return NULL;
+ };
+ if(size!=NULL) *size = len;
+ return buf;
+};
+
+void endianswap(void *memory, int stride, int length) // little indians as storage format
+{
+ if(*((char *)&stride)) return;
+ loop(w, length) loop(i, stride/2)
+ {
+ uchar *p = (uchar *)memory+w*stride;
+ uchar t = p[i];
+ p[i] = p[stride-i-1];
+ p[stride-i-1] = t;
+ };
+}
DELETED src/weapon.cpp
Index: src/weapon.cpp
==================================================================
--- src/weapon.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-// weapon.cpp: all shooting and effects code
-
-#include "cube.h"
-
-struct guninfo { short sound, attackdelay, damage, projspeed, part, kickamount; char *name; };
-
-const int MONSTERDAMAGEFACTOR = 4;
-const int SGRAYS = 20;
-const float SGSPREAD = 2;
-vec sg[SGRAYS];
-
-guninfo guns[NUMGUNS] =
-{
- { S_PUNCH1, 250, 50, 0, 0, 1, "fist" },
- { S_SG, 1400, 10, 0, 0, 20, "shotgun" }, // *SGRAYS
- { S_CG, 100, 30, 0, 0, 7, "chaingun" },
- { S_RLFIRE, 800, 120, 80, 0, 10, "rocketlauncher" },
- { S_RIFLE, 1500, 100, 0, 0, 30, "rifle" },
- { S_FLAUNCH, 200, 20, 50, 4, 1, "fireball" },
- { S_ICEBALL, 200, 40, 30, 6, 1, "iceball" },
- { S_SLIMEBALL, 200, 30, 160, 7, 1, "slimeball" },
- { S_PIGR1, 250, 50, 0, 0, 1, "bite" },
-};
-
-void selectgun(int a, int b, int c)
-{
- if(a<-1 || b<-1 || c<-1 || a>=NUMGUNS || b>=NUMGUNS || c>=NUMGUNS) return;
- int s = player1->gunselect;
- if(a>=0 && s!=a && player1->ammo[a]) s = a;
- else if(b>=0 && s!=b && player1->ammo[b]) s = b;
- else if(c>=0 && s!=c && player1->ammo[c]) s = c;
- else if(s!=GUN_RL && player1->ammo[GUN_RL]) s = GUN_RL;
- else if(s!=GUN_CG && player1->ammo[GUN_CG]) s = GUN_CG;
- else if(s!=GUN_SG && player1->ammo[GUN_SG]) s = GUN_SG;
- else if(s!=GUN_RIFLE && player1->ammo[GUN_RIFLE]) s = GUN_RIFLE;
- else s = GUN_FIST;
- if(s!=player1->gunselect) playsoundc(S_WEAPLOAD);
- player1->gunselect = s;
- //conoutf("%s selected", (int)guns[s].name);
-};
-
-int reloadtime(int gun) { return guns[gun].attackdelay; };
-
-void weapon(char *a1, char *a2, char *a3)
-{
- selectgun(a1[0] ? atoi(a1) : -1,
- a2[0] ? atoi(a2) : -1,
- a3[0] ? atoi(a3) : -1);
-};
-
-COMMAND(weapon, ARG_3STR);
-
-void createrays(vec &from, vec &to) // create random spread of rays for the shotgun
-{
- vdist(dist, dvec, from, to);
- float f = dist*SGSPREAD/1000;
- loopi(SGRAYS)
- {
- #define RNDD (rnd(101)-50)*f
- vec r = { RNDD, RNDD, RNDD };
- sg[i] = to;
- vadd(sg[i], r);
- };
-};
-
-bool intersect(dynent *d, vec &from, vec &to) // if lineseg hits entity bounding box
-{
- vec v = to, w = d->o, *p;
- vsub(v, from);
- vsub(w, from);
- float c1 = dotprod(w, v);
-
- if(c1<=0) p = &from;
- else
- {
- float c2 = dotprod(v, v);
- if(c2<=c1) p = &to;
- else
- {
- float f = c1/c2;
- vmul(v, f);
- vadd(v, from);
- p = &v;
- };
- };
-
- return p->x <= d->o.x+d->radius
- && p->x >= d->o.x-d->radius
- && p->y <= d->o.y+d->radius
- && p->y >= d->o.y-d->radius
- && p->z <= d->o.z+d->aboveeye
- && p->z >= d->o.z-d->eyeheight;
-};
-
-char *playerincrosshair()
-{
- if(demoplayback) return NULL;
- loopv(players)
- {
- dynent *o = players[i];
- if(!o) continue;
- if(intersect(o, player1->o, worldpos)) return o->name;
- };
- return NULL;
-};
-
-const int MAXPROJ = 100;
-struct projectile { vec o, to; float speed; dynent *owner; int gun; bool inuse, local; };
-projectile projs[MAXPROJ];
-
-void projreset() { loopi(MAXPROJ) projs[i].inuse = false; };
-
-void newprojectile(vec &from, vec &to, float speed, bool local, dynent *owner, int gun)
-{
- loopi(MAXPROJ)
- {
- projectile *p = &projs[i];
- if(p->inuse) continue;
- p->inuse = true;
- p->o = from;
- p->to = to;
- p->speed = speed;
- p->local = local;
- p->owner = owner;
- p->gun = gun;
- return;
- };
-};
-
-void hit(int target, int damage, dynent *d, dynent *at)
-{
- if(d==player1) selfdamage(damage, at==player1 ? -1 : -2, at);
- else if(d->monsterstate) monsterpain(d, damage, at);
- else { addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); };
- particle_splash(3, damage, 1000, d->o);
- demodamage(damage, d->o);
-};
-
-const float RL_RADIUS = 5;
-const float RL_DAMRAD = 7; // hack
-
-void radialeffect(dynent *o, vec &v, int cn, int qdam, dynent *at)
-{
- if(o->state!=CS_ALIVE) return;
- vdist(dist, temp, v, o->o);
- dist -= 2; // account for eye distance imprecision
- if(distvel, temp);
- };
-};
-
-void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int notthismonster, int qdam)
-{
- particle_splash(0, 50, 300, v);
- p->inuse = false;
- if(p->gun!=GUN_RL)
- {
- playsound(S_FEXPLODE, &v);
- // no push?
- }
- else
- {
- playsound(S_RLHIT, &v);
- newsphere(v, RL_RADIUS, 0);
- dodynlight(vold, v, 0, 0, p->owner);
- if(!p->local) return;
- radialeffect(player1, v, -1, qdam, p->owner);
- loopv(players)
- {
- if(i==notthisplayer) continue;
- dynent *o = players[i];
- if(!o) continue;
- radialeffect(o, v, i, qdam, p->owner);
- };
- dvector &mv = getmonsters();
- loopv(mv) if(i!=notthismonster) radialeffect(mv[i], v, i, qdam, p->owner);
- };
-};
-
-inline void projdamage(dynent *o, projectile *p, vec &v, int i, int im, int qdam)
-{
- if(o->state!=CS_ALIVE) return;
- if(intersect(o, p->o, v))
- {
- splash(p, v, p->o, i, im, qdam);
- hit(i, qdam, o, p->owner);
- };
-};
-
-void moveprojectiles(float time)
-{
- loopi(MAXPROJ)
- {
- projectile *p = &projs[i];
- if(!p->inuse) continue;
- int qdam = guns[p->gun].damage*(p->owner->quadmillis ? 4 : 1);
- if(p->owner->monsterstate) qdam /= MONSTERDAMAGEFACTOR;
- vdist(dist, v, p->o, p->to);
- float dtime = dist*1000/p->speed;
- if(time>dtime) dtime = time;
- vmul(v, time/dtime);
- vadd(v, p->o)
- if(p->local)
- {
- loopv(players)
- {
- dynent *o = players[i];
- if(!o) continue;
- projdamage(o, p, v, i, -1, qdam);
- };
- if(p->owner!=player1) projdamage(player1, p, v, -1, -1, qdam);
- dvector &mv = getmonsters();
- loopv(mv) if(!vreject(mv[i]->o, v, 10.0f) && mv[i]!=p->owner) projdamage(mv[i], p, v, -1, i, qdam);
- };
- if(p->inuse)
- {
- if(time==dtime) splash(p, v, p->o, -1, -1, qdam);
- else
- {
- if(p->gun==GUN_RL) { dodynlight(p->o, v, 0, 255, p->owner); particle_splash(5, 2, 200, v); }
- else { particle_splash(1, 1, 200, v); particle_splash(guns[p->gun].part, 1, 1, v); };
- };
- };
- p->o = v;
- };
-};
-
-void shootv(int gun, vec &from, vec &to, dynent *d, bool local) // create visual effect from a shot
-{
- playsound(guns[gun].sound, d==player1 ? NULL : &d->o);
- int pspeed = 25;
- switch(gun)
- {
- case GUN_FIST:
- break;
-
- case GUN_SG:
- {
- loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]);
- break;
- };
-
- case GUN_CG:
- particle_splash(0, 100, 250, to);
- //particle_trail(1, 10, from, to);
- break;
-
- case GUN_RL:
- case GUN_FIREBALL:
- case GUN_ICEBALL:
- case GUN_SLIMEBALL:
- pspeed = guns[gun].projspeed;
- if(d->monsterstate) pspeed /= 2;
- newprojectile(from, to, (float)pspeed, local, d, gun);
- break;
-
- case GUN_RIFLE:
- particle_splash(0, 50, 200, to);
- particle_trail(1, 500, from, to);
- break;
- };
-};
-
-void hitpush(int target, int damage, dynent *d, dynent *at, vec &from, vec &to)
-{
- hit(target, damage, d, at);
- vdist(dist, v, from, to);
- vmul(v, damage/dist/50);
- vadd(d->vel, v);
-};
-
-void raydamage(dynent *o, vec &from, vec &to, dynent *d, int i)
-{
- if(o->state!=CS_ALIVE) return;
- int qdam = guns[d->gunselect].damage;
- if(d->quadmillis) qdam *= 4;
- if(d->monsterstate) qdam /= MONSTERDAMAGEFACTOR;
- if(d->gunselect==GUN_SG)
- {
- int damage = 0;
- loop(r, SGRAYS) if(intersect(o, from, sg[r])) damage += qdam;
- if(damage) hitpush(i, damage, o, d, from, to);
- }
- else if(intersect(o, from, to)) hitpush(i, qdam, o, d, from, to);
-};
-
-void shoot(dynent *d, vec &targ)
-{
- int attacktime = lastmillis-d->lastaction;
- if(attacktimegunwait) return;
- d->gunwait = 0;
- if(!d->attacking) return;
- d->lastaction = lastmillis;
- d->lastattackgun = d->gunselect;
- if(!d->ammo[d->gunselect]) { playsoundc(S_NOAMMO); d->gunwait = 250; d->lastattackgun = -1; return; };
- if(d->gunselect) d->ammo[d->gunselect]--;
- vec from = d->o;
- vec to = targ;
- from.z -= 0.2f; // below eye
-
- vdist(dist, unitv, from, to);
- vdiv(unitv, dist);
- vec kickback = unitv;
- vmul(kickback, guns[d->gunselect].kickamount*-0.01f);
- vadd(d->vel, kickback);
- if(d->pitch<80.0f) d->pitch += guns[d->gunselect].kickamount*0.05f;
-
-
- if(d->gunselect==GUN_FIST || d->gunselect==GUN_BITE)
- {
- vmul(unitv, 3); // punch range
- to = from;
- vadd(to, unitv);
- };
- if(d->gunselect==GUN_SG) createrays(from, to);
-
- if(d->quadmillis && attacktime>200) playsoundc(S_ITEMPUP);
- shootv(d->gunselect, from, to, d, true);
- if(!d->monsterstate) addmsg(1, 8, SV_SHOT, d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF));
- d->gunwait = guns[d->gunselect].attackdelay;
-
- if(guns[d->gunselect].projspeed) return;
-
- loopv(players)
- {
- dynent *o = players[i];
- if(!o) continue;
- raydamage(o, from, to, d, i);
- };
-
- dvector &v = getmonsters();
- loopv(v) if(v[i]!=d) raydamage(v[i], from, to, d, -2);
-
- if(d->monsterstate) raydamage(player1, from, to, d, -1);
-};
-
-
ADDED src/weapon.cxx
Index: src/weapon.cxx
==================================================================
--- /dev/null
+++ src/weapon.cxx
@@ -0,0 +1,342 @@
+// weapon.cpp: all shooting and effects code
+
+#include "cube.h"
+
+struct guninfo { short sound, attackdelay, damage, projspeed, part, kickamount; char *name; };
+
+const int MONSTERDAMAGEFACTOR = 4;
+const int SGRAYS = 20;
+const float SGSPREAD = 2;
+vec sg[SGRAYS];
+
+guninfo guns[NUMGUNS] =
+{
+ { S_PUNCH1, 250, 50, 0, 0, 1, "fist" },
+ { S_SG, 1400, 10, 0, 0, 20, "shotgun" }, // *SGRAYS
+ { S_CG, 100, 30, 0, 0, 7, "chaingun" },
+ { S_RLFIRE, 800, 120, 80, 0, 10, "rocketlauncher" },
+ { S_RIFLE, 1500, 100, 0, 0, 30, "rifle" },
+ { S_FLAUNCH, 200, 20, 50, 4, 1, "fireball" },
+ { S_ICEBALL, 200, 40, 30, 6, 1, "iceball" },
+ { S_SLIMEBALL, 200, 30, 160, 7, 1, "slimeball" },
+ { S_PIGR1, 250, 50, 0, 0, 1, "bite" },
+};
+
+void selectgun(int a, int b, int c)
+{
+ if(a<-1 || b<-1 || c<-1 || a>=NUMGUNS || b>=NUMGUNS || c>=NUMGUNS) return;
+ int s = player1->gunselect;
+ if(a>=0 && s!=a && player1->ammo[a]) s = a;
+ else if(b>=0 && s!=b && player1->ammo[b]) s = b;
+ else if(c>=0 && s!=c && player1->ammo[c]) s = c;
+ else if(s!=GUN_RL && player1->ammo[GUN_RL]) s = GUN_RL;
+ else if(s!=GUN_CG && player1->ammo[GUN_CG]) s = GUN_CG;
+ else if(s!=GUN_SG && player1->ammo[GUN_SG]) s = GUN_SG;
+ else if(s!=GUN_RIFLE && player1->ammo[GUN_RIFLE]) s = GUN_RIFLE;
+ else s = GUN_FIST;
+ if(s!=player1->gunselect) playsoundc(S_WEAPLOAD);
+ player1->gunselect = s;
+ //conoutf("%s selected", (int)guns[s].name);
+};
+
+int reloadtime(int gun) { return guns[gun].attackdelay; };
+
+void weapon(char *a1, char *a2, char *a3)
+{
+ selectgun(a1[0] ? atoi(a1) : -1,
+ a2[0] ? atoi(a2) : -1,
+ a3[0] ? atoi(a3) : -1);
+};
+
+COMMAND(weapon, ARG_3STR);
+
+void createrays(vec &from, vec &to) // create random spread of rays for the shotgun
+{
+ vdist(dist, dvec, from, to);
+ float f = dist*SGSPREAD/1000;
+ loopi(SGRAYS)
+ {
+ #define RNDD (rnd(101)-50)*f
+ vec r = { RNDD, RNDD, RNDD };
+ sg[i] = to;
+ vadd(sg[i], r);
+ };
+};
+
+bool intersect(dynent *d, vec &from, vec &to) // if lineseg hits entity bounding box
+{
+ vec v = to, w = d->o, *p;
+ vsub(v, from);
+ vsub(w, from);
+ float c1 = dotprod(w, v);
+
+ if(c1<=0) p = &from;
+ else
+ {
+ float c2 = dotprod(v, v);
+ if(c2<=c1) p = &to;
+ else
+ {
+ float f = c1/c2;
+ vmul(v, f);
+ vadd(v, from);
+ p = &v;
+ };
+ };
+
+ return p->x <= d->o.x+d->radius
+ && p->x >= d->o.x-d->radius
+ && p->y <= d->o.y+d->radius
+ && p->y >= d->o.y-d->radius
+ && p->z <= d->o.z+d->aboveeye
+ && p->z >= d->o.z-d->eyeheight;
+};
+
+char *playerincrosshair()
+{
+ if(demoplayback) return NULL;
+ loopv(players)
+ {
+ dynent *o = players[i];
+ if(!o) continue;
+ if(intersect(o, player1->o, worldpos)) return o->name;
+ };
+ return NULL;
+};
+
+const int MAXPROJ = 100;
+struct projectile { vec o, to; float speed; dynent *owner; int gun; bool inuse, local; };
+projectile projs[MAXPROJ];
+
+void projreset() { loopi(MAXPROJ) projs[i].inuse = false; };
+
+void newprojectile(vec &from, vec &to, float speed, bool local, dynent *owner, int gun)
+{
+ loopi(MAXPROJ)
+ {
+ projectile *p = &projs[i];
+ if(p->inuse) continue;
+ p->inuse = true;
+ p->o = from;
+ p->to = to;
+ p->speed = speed;
+ p->local = local;
+ p->owner = owner;
+ p->gun = gun;
+ return;
+ };
+};
+
+void hit(int target, int damage, dynent *d, dynent *at)
+{
+ if(d==player1) selfdamage(damage, at==player1 ? -1 : -2, at);
+ else if(d->monsterstate) monsterpain(d, damage, at);
+ else { addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); };
+ particle_splash(3, damage, 1000, d->o);
+ demodamage(damage, d->o);
+};
+
+const float RL_RADIUS = 5;
+const float RL_DAMRAD = 7; // hack
+
+void radialeffect(dynent *o, vec &v, int cn, int qdam, dynent *at)
+{
+ if(o->state!=CS_ALIVE) return;
+ vdist(dist, temp, v, o->o);
+ dist -= 2; // account for eye distance imprecision
+ if(distvel, temp);
+ };
+};
+
+void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int notthismonster, int qdam)
+{
+ particle_splash(0, 50, 300, v);
+ p->inuse = false;
+ if(p->gun!=GUN_RL)
+ {
+ playsound(S_FEXPLODE, &v);
+ // no push?
+ }
+ else
+ {
+ playsound(S_RLHIT, &v);
+ newsphere(v, RL_RADIUS, 0);
+ dodynlight(vold, v, 0, 0, p->owner);
+ if(!p->local) return;
+ radialeffect(player1, v, -1, qdam, p->owner);
+ loopv(players)
+ {
+ if(i==notthisplayer) continue;
+ dynent *o = players[i];
+ if(!o) continue;
+ radialeffect(o, v, i, qdam, p->owner);
+ };
+ dvector &mv = getmonsters();
+ loopv(mv) if(i!=notthismonster) radialeffect(mv[i], v, i, qdam, p->owner);
+ };
+};
+
+inline void projdamage(dynent *o, projectile *p, vec &v, int i, int im, int qdam)
+{
+ if(o->state!=CS_ALIVE) return;
+ if(intersect(o, p->o, v))
+ {
+ splash(p, v, p->o, i, im, qdam);
+ hit(i, qdam, o, p->owner);
+ };
+};
+
+void moveprojectiles(float time)
+{
+ loopi(MAXPROJ)
+ {
+ projectile *p = &projs[i];
+ if(!p->inuse) continue;
+ int qdam = guns[p->gun].damage*(p->owner->quadmillis ? 4 : 1);
+ if(p->owner->monsterstate) qdam /= MONSTERDAMAGEFACTOR;
+ vdist(dist, v, p->o, p->to);
+ float dtime = dist*1000/p->speed;
+ if(time>dtime) dtime = time;
+ vmul(v, time/dtime);
+ vadd(v, p->o)
+ if(p->local)
+ {
+ loopv(players)
+ {
+ dynent *o = players[i];
+ if(!o) continue;
+ projdamage(o, p, v, i, -1, qdam);
+ };
+ if(p->owner!=player1) projdamage(player1, p, v, -1, -1, qdam);
+ dvector &mv = getmonsters();
+ loopv(mv) if(!vreject(mv[i]->o, v, 10.0f) && mv[i]!=p->owner) projdamage(mv[i], p, v, -1, i, qdam);
+ };
+ if(p->inuse)
+ {
+ if(time==dtime) splash(p, v, p->o, -1, -1, qdam);
+ else
+ {
+ if(p->gun==GUN_RL) { dodynlight(p->o, v, 0, 255, p->owner); particle_splash(5, 2, 200, v); }
+ else { particle_splash(1, 1, 200, v); particle_splash(guns[p->gun].part, 1, 1, v); };
+ };
+ };
+ p->o = v;
+ };
+};
+
+void shootv(int gun, vec &from, vec &to, dynent *d, bool local) // create visual effect from a shot
+{
+ playsound(guns[gun].sound, d==player1 ? NULL : &d->o);
+ int pspeed = 25;
+ switch(gun)
+ {
+ case GUN_FIST:
+ break;
+
+ case GUN_SG:
+ {
+ loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]);
+ break;
+ };
+
+ case GUN_CG:
+ particle_splash(0, 100, 250, to);
+ //particle_trail(1, 10, from, to);
+ break;
+
+ case GUN_RL:
+ case GUN_FIREBALL:
+ case GUN_ICEBALL:
+ case GUN_SLIMEBALL:
+ pspeed = guns[gun].projspeed;
+ if(d->monsterstate) pspeed /= 2;
+ newprojectile(from, to, (float)pspeed, local, d, gun);
+ break;
+
+ case GUN_RIFLE:
+ particle_splash(0, 50, 200, to);
+ particle_trail(1, 500, from, to);
+ break;
+ };
+};
+
+void hitpush(int target, int damage, dynent *d, dynent *at, vec &from, vec &to)
+{
+ hit(target, damage, d, at);
+ vdist(dist, v, from, to);
+ vmul(v, damage/dist/50);
+ vadd(d->vel, v);
+};
+
+void raydamage(dynent *o, vec &from, vec &to, dynent *d, int i)
+{
+ if(o->state!=CS_ALIVE) return;
+ int qdam = guns[d->gunselect].damage;
+ if(d->quadmillis) qdam *= 4;
+ if(d->monsterstate) qdam /= MONSTERDAMAGEFACTOR;
+ if(d->gunselect==GUN_SG)
+ {
+ int damage = 0;
+ loop(r, SGRAYS) if(intersect(o, from, sg[r])) damage += qdam;
+ if(damage) hitpush(i, damage, o, d, from, to);
+ }
+ else if(intersect(o, from, to)) hitpush(i, qdam, o, d, from, to);
+};
+
+void shoot(dynent *d, vec &targ)
+{
+ int attacktime = lastmillis-d->lastaction;
+ if(attacktimegunwait) return;
+ d->gunwait = 0;
+ if(!d->attacking) return;
+ d->lastaction = lastmillis;
+ d->lastattackgun = d->gunselect;
+ if(!d->ammo[d->gunselect]) { playsoundc(S_NOAMMO); d->gunwait = 250; d->lastattackgun = -1; return; };
+ if(d->gunselect) d->ammo[d->gunselect]--;
+ vec from = d->o;
+ vec to = targ;
+ from.z -= 0.2f; // below eye
+
+ vdist(dist, unitv, from, to);
+ vdiv(unitv, dist);
+ vec kickback = unitv;
+ vmul(kickback, guns[d->gunselect].kickamount*-0.01f);
+ vadd(d->vel, kickback);
+ if(d->pitch<80.0f) d->pitch += guns[d->gunselect].kickamount*0.05f;
+
+
+ if(d->gunselect==GUN_FIST || d->gunselect==GUN_BITE)
+ {
+ vmul(unitv, 3); // punch range
+ to = from;
+ vadd(to, unitv);
+ };
+ if(d->gunselect==GUN_SG) createrays(from, to);
+
+ if(d->quadmillis && attacktime>200) playsoundc(S_ITEMPUP);
+ shootv(d->gunselect, from, to, d, true);
+ if(!d->monsterstate) addmsg(1, 8, SV_SHOT, d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF));
+ d->gunwait = guns[d->gunselect].attackdelay;
+
+ if(guns[d->gunselect].projspeed) return;
+
+ loopv(players)
+ {
+ dynent *o = players[i];
+ if(!o) continue;
+ raydamage(o, from, to, d, i);
+ };
+
+ dvector &v = getmonsters();
+ loopv(v) if(v[i]!=d) raydamage(v[i], from, to, d, -2);
+
+ if(d->monsterstate) raydamage(player1, from, to, d, -1);
+};
+
+
DELETED src/world.cpp
Index: src/world.cpp
==================================================================
--- src/world.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-// world.cpp: core map management stuff
-
-#include "cube.h"
-
-extern char *entnames[]; // lookup from map entities above to strings
-
-sqr *world = NULL;
-int sfactor, ssize, cubicsize, mipsize;
-
-header hdr;
-
-void settag(int tag, int type) // set all cubes with "tag" to space, if tag is 0 then reset ALL tagged cubes according to type
-{
- int maxx = 0, maxy = 0, minx = ssize, miny = ssize;
- loop(x, ssize) loop(y, ssize)
- {
- sqr *s = S(x, y);
- if(s->tag)
- {
- if(tag)
- {
- if(tag==s->tag) s->type = SPACE;
- else continue;
- }
- else
- {
- s->type = type ? SOLID : SPACE;
- };
- if(x>maxx) maxx = x;
- if(y>maxy) maxy = y;
- if(x=SMALLEST_FACTOR) return;
- int lighterr = getvar("lighterror")*3;
- sqr *w = wmip[level];
- sqr *v = wmip[level+1];
- int ws = ssize>>level;
- int vs = ssize>>(level+1);
- block s = b;
- if(s.x&1) { s.x--; s.xs++; };
- if(s.y&1) { s.y--; s.ys++; };
- s.xs = (s.xs+1)&~1;
- s.ys = (s.ys+1)&~1;
- for(int x = s.x; xtype]++;
- r->type = SEMISOLID; // cube contains both solid and space, treated specially in the renderer
- loopk(MAXTYPE) if(nums[k]==4) r->type = k;
- if(!SOLID(r))
- {
- int floor = 127, ceil = -128, num = 0;
- loopi(4) if(!SOLID(o[i]))
- {
- num++;
- int fh = o[i]->floor;
- int ch = o[i]->ceil;
- if(r->type==SEMISOLID)
- {
- if(o[i]->type==FHF) fh -= o[i]->vdelta/4+2; // crap hack, needed for rendering large mips next to hfs
- if(o[i]->type==CHF) ch += o[i]->vdelta/4+2; // FIXME: needs to somehow take into account middle vertices on higher mips
- };
- if(fhceil) ceil = ch;
- };
- r->floor = floor;
- r->ceil = ceil;
- };
- if(r->type==CORNER) goto mip; // special case: don't ever split even if textures etc are different
- r->defer = 1;
- if(SOLID(r))
- {
- loopi(3)
- {
- if(o[i]->wtex!=o[3]->wtex) goto c; // on an all solid cube, only thing that needs to be equal for a perfect mip is the wall texture
- };
- }
- else
- {
- loopi(3)
- {
- if(o[i]->type!=o[3]->type
- || o[i]->floor!=o[3]->floor
- || o[i]->ceil!=o[3]->ceil
- || o[i]->ftex!=o[3]->ftex
- || o[i]->ctex!=o[3]->ctex
- || abs(o[i+1]->r-o[0]->r)>lighterr // perfect mip even if light is not exactly equal
- || abs(o[i+1]->g-o[0]->g)>lighterr
- || abs(o[i+1]->b-o[0]->b)>lighterr
- || o[i]->utex!=o[3]->utex
- || o[i]->wtex!=o[3]->wtex) goto c;
- };
- if(r->type==CHF || r->type==FHF) // can make a perfect mip out of a hf if slopes lie on one line
- {
- if(o[0]->vdelta-o[1]->vdelta != o[1]->vdelta-SWS(w,x+2,y,ws)->vdelta
- || o[0]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+2,ws)->vdelta
- || o[0]->vdelta-o[3]->vdelta != o[3]->vdelta-SWS(w,x,y+2,ws)->vdelta
- || o[3]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+1,ws)->vdelta
- || o[1]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+1,y+2,ws)->vdelta) goto c;
- };
- };
- { loopi(4) if(o[i]->defer) goto c; }; // if any of the constituents is not perfect, then this one isn't either
- mip:
- r->defer = 0;
- c:;
- };
- s.x /= 2;
- s.y /= 2;
- s.xs /= 2;
- s.ys /= 2;
- remip(s, level+1);
-};
-
-void remipmore(block &b, int level)
-{
- block bb = b;
- if(bb.x>1) bb.x--;
- if(bb.y>1) bb.y--;
- if(bb.xso, v);
- if(dist32) v1 = 32;
- if(!v1) e.attr1 = 16;
- if(!v2 && !v3 && !v4) e.attr2 = 255;
- break;
-
- case MAPMODEL:
- e.attr4 = e.attr3;
- e.attr3 = e.attr2;
- case MONSTER:
- case TELEDEST:
- e.attr2 = (uchar)e.attr1;
- case PLAYERSTART:
- e.attr1 = (int)player1->yaw;
- break;
- };
- addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4);
- ents.add(*((entity *)&e)); // unsafe!
- if(type==LIGHT) calclight();
- return &ents.last();
-};
-
-void clearents(char *name)
-{
- int type = findtype(name);
- if(noteditmode() || multiplayer()) return;
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type==type) e.type = NOTUSED;
- };
- if(type==LIGHT) calclight();
-};
-
-COMMAND(clearents, ARG_1STR);
-
-void scalecomp(uchar &c, int intens)
-{
- int n = c*intens/100;
- if(n>255) n = 255;
- c = n;
-};
-
-void scalelights(int f, int intens)
-{
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type!=LIGHT) continue;
- e.attr1 = e.attr1*f/100;
- if(e.attr1<2) e.attr1 = 2;
- if(e.attr1>32) e.attr1 = 32;
- if(intens)
- {
- scalecomp(e.attr2, intens);
- scalecomp(e.attr3, intens);
- scalecomp(e.attr4, intens);
- };
- };
- calclight();
-};
-
-COMMAND(scalelights, ARG_2INT);
-
-int findentity(int type, int index)
-{
- for(int i = index; i>(i*2); };
-};
-
-void empty_world(int factor, bool force) // main empty world creation routine, if passed factor -1 will enlarge old world by 1
-{
- if(!force && noteditmode()) return;
- cleardlights();
- pruneundos();
- sqr *oldworld = world;
- bool copy = false;
- if(oldworld && factor<0) { factor = sfactor+1; copy = true; };
- if(factorLARGEST_FACTOR) factor = LARGEST_FACTOR;
- setupworld(factor);
-
- loop(x,ssize) loop(y,ssize)
- {
- sqr *s = S(x,y);
- s->r = s->g = s->b = 150;
- s->ftex = DEFAULT_FLOOR;
- s->ctex = DEFAULT_CEIL;
- s->wtex = s->utex = DEFAULT_WALL;
- s->type = SOLID;
- s->floor = 0;
- s->ceil = 16;
- s->vdelta = 0;
- s->defer = 0;
- };
-
- strncpy(hdr.head, "CUBE", 4);
- hdr.version = MAPVERSION;
- hdr.headersize = sizeof(header);
- hdr.sfactor = sfactor;
-
- if(copy)
- {
- loop(x,ssize/2) loop(y,ssize/2)
- {
- *S(x+ssize/4, y+ssize/4) = *SWS(oldworld, x, y, ssize/2);
- };
- loopv(ents)
- {
- ents[i].x += ssize/4;
- ents[i].y += ssize/4;
- };
- }
- else
- {
- strn0cpy(hdr.maptitle, "Untitled Map by Unknown", 128);
- hdr.waterlevel = -100000;
- loopi(15) hdr.reserved[i] = 0;
- loopk(3) loopi(256) hdr.texlists[k][i] = i;
- ents.setsize(0);
- block b = { 8, 8, ssize-16, ssize-16 };
- edittypexy(SPACE, b);
- };
-
- calclight();
- startmap("base/unnamed");
- if(oldworld)
- {
- free(oldworld);
- toggleedit();
- execute("fullbright 1");
- };
-};
-
-void mapenlarge() { empty_world(-1, false); };
-void newmap(int i) { empty_world(i, false); };
-
-COMMAND(mapenlarge, ARG_NONE);
-COMMAND(newmap, ARG_1INT);
-COMMANDN(recalc, calclight, ARG_NONE);
-COMMAND(delent, ARG_NONE);
-COMMAND(entproperty, ARG_2INT);
-
ADDED src/world.cxx
Index: src/world.cxx
==================================================================
--- /dev/null
+++ src/world.cxx
@@ -0,0 +1,372 @@
+// world.cpp: core map management stuff
+
+#include "cube.h"
+
+extern char *entnames[]; // lookup from map entities above to strings
+
+sqr *world = NULL;
+int sfactor, ssize, cubicsize, mipsize;
+
+header hdr;
+
+void settag(int tag, int type) // set all cubes with "tag" to space, if tag is 0 then reset ALL tagged cubes according to type
+{
+ int maxx = 0, maxy = 0, minx = ssize, miny = ssize;
+ loop(x, ssize) loop(y, ssize)
+ {
+ sqr *s = S(x, y);
+ if(s->tag)
+ {
+ if(tag)
+ {
+ if(tag==s->tag) s->type = SPACE;
+ else continue;
+ }
+ else
+ {
+ s->type = type ? SOLID : SPACE;
+ };
+ if(x>maxx) maxx = x;
+ if(y>maxy) maxy = y;
+ if(x=SMALLEST_FACTOR) return;
+ int lighterr = getvar("lighterror")*3;
+ sqr *w = wmip[level];
+ sqr *v = wmip[level+1];
+ int ws = ssize>>level;
+ int vs = ssize>>(level+1);
+ block s = b;
+ if(s.x&1) { s.x--; s.xs++; };
+ if(s.y&1) { s.y--; s.ys++; };
+ s.xs = (s.xs+1)&~1;
+ s.ys = (s.ys+1)&~1;
+ for(int x = s.x; xtype]++;
+ r->type = SEMISOLID; // cube contains both solid and space, treated specially in the renderer
+ loopk(MAXTYPE) if(nums[k]==4) r->type = k;
+ if(!SOLID(r))
+ {
+ int floor = 127, ceil = -128, num = 0;
+ loopi(4) if(!SOLID(o[i]))
+ {
+ num++;
+ int fh = o[i]->floor;
+ int ch = o[i]->ceil;
+ if(r->type==SEMISOLID)
+ {
+ if(o[i]->type==FHF) fh -= o[i]->vdelta/4+2; // crap hack, needed for rendering large mips next to hfs
+ if(o[i]->type==CHF) ch += o[i]->vdelta/4+2; // FIXME: needs to somehow take into account middle vertices on higher mips
+ };
+ if(fhceil) ceil = ch;
+ };
+ r->floor = floor;
+ r->ceil = ceil;
+ };
+ if(r->type==CORNER) goto mip; // special case: don't ever split even if textures etc are different
+ r->defer = 1;
+ if(SOLID(r))
+ {
+ loopi(3)
+ {
+ if(o[i]->wtex!=o[3]->wtex) goto c; // on an all solid cube, only thing that needs to be equal for a perfect mip is the wall texture
+ };
+ }
+ else
+ {
+ loopi(3)
+ {
+ if(o[i]->type!=o[3]->type
+ || o[i]->floor!=o[3]->floor
+ || o[i]->ceil!=o[3]->ceil
+ || o[i]->ftex!=o[3]->ftex
+ || o[i]->ctex!=o[3]->ctex
+ || abs(o[i+1]->r-o[0]->r)>lighterr // perfect mip even if light is not exactly equal
+ || abs(o[i+1]->g-o[0]->g)>lighterr
+ || abs(o[i+1]->b-o[0]->b)>lighterr
+ || o[i]->utex!=o[3]->utex
+ || o[i]->wtex!=o[3]->wtex) goto c;
+ };
+ if(r->type==CHF || r->type==FHF) // can make a perfect mip out of a hf if slopes lie on one line
+ {
+ if(o[0]->vdelta-o[1]->vdelta != o[1]->vdelta-SWS(w,x+2,y,ws)->vdelta
+ || o[0]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+2,ws)->vdelta
+ || o[0]->vdelta-o[3]->vdelta != o[3]->vdelta-SWS(w,x,y+2,ws)->vdelta
+ || o[3]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+1,ws)->vdelta
+ || o[1]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+1,y+2,ws)->vdelta) goto c;
+ };
+ };
+ { loopi(4) if(o[i]->defer) goto c; }; // if any of the constituents is not perfect, then this one isn't either
+ mip:
+ r->defer = 0;
+ c:;
+ };
+ s.x /= 2;
+ s.y /= 2;
+ s.xs /= 2;
+ s.ys /= 2;
+ remip(s, level+1);
+};
+
+void remipmore(block &b, int level)
+{
+ block bb = b;
+ if(bb.x>1) bb.x--;
+ if(bb.y>1) bb.y--;
+ if(bb.xso, v);
+ if(dist32) v1 = 32;
+ if(!v1) e.attr1 = 16;
+ if(!v2 && !v3 && !v4) e.attr2 = 255;
+ break;
+
+ case MAPMODEL:
+ e.attr4 = e.attr3;
+ e.attr3 = e.attr2;
+ case MONSTER:
+ case TELEDEST:
+ e.attr2 = (uchar)e.attr1;
+ case PLAYERSTART:
+ e.attr1 = (int)player1->yaw;
+ break;
+ };
+ addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4);
+ ents.add(*((entity *)&e)); // unsafe!
+ if(type==LIGHT) calclight();
+ return &ents.last();
+};
+
+void clearents(char *name)
+{
+ int type = findtype(name);
+ if(noteditmode() || multiplayer()) return;
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type==type) e.type = NOTUSED;
+ };
+ if(type==LIGHT) calclight();
+};
+
+COMMAND(clearents, ARG_1STR);
+
+void scalecomp(uchar &c, int intens)
+{
+ int n = c*intens/100;
+ if(n>255) n = 255;
+ c = n;
+};
+
+void scalelights(int f, int intens)
+{
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type!=LIGHT) continue;
+ e.attr1 = e.attr1*f/100;
+ if(e.attr1<2) e.attr1 = 2;
+ if(e.attr1>32) e.attr1 = 32;
+ if(intens)
+ {
+ scalecomp(e.attr2, intens);
+ scalecomp(e.attr3, intens);
+ scalecomp(e.attr4, intens);
+ };
+ };
+ calclight();
+};
+
+COMMAND(scalelights, ARG_2INT);
+
+int findentity(int type, int index)
+{
+ for(int i = index; i>(i*2); };
+};
+
+void empty_world(int factor, bool force) // main empty world creation routine, if passed factor -1 will enlarge old world by 1
+{
+ if(!force && noteditmode()) return;
+ cleardlights();
+ pruneundos();
+ sqr *oldworld = world;
+ bool copy = false;
+ if(oldworld && factor<0) { factor = sfactor+1; copy = true; };
+ if(factorLARGEST_FACTOR) factor = LARGEST_FACTOR;
+ setupworld(factor);
+
+ loop(x,ssize) loop(y,ssize)
+ {
+ sqr *s = S(x,y);
+ s->r = s->g = s->b = 150;
+ s->ftex = DEFAULT_FLOOR;
+ s->ctex = DEFAULT_CEIL;
+ s->wtex = s->utex = DEFAULT_WALL;
+ s->type = SOLID;
+ s->floor = 0;
+ s->ceil = 16;
+ s->vdelta = 0;
+ s->defer = 0;
+ };
+
+ strncpy(hdr.head, "CUBE", 4);
+ hdr.version = MAPVERSION;
+ hdr.headersize = sizeof(header);
+ hdr.sfactor = sfactor;
+
+ if(copy)
+ {
+ loop(x,ssize/2) loop(y,ssize/2)
+ {
+ *S(x+ssize/4, y+ssize/4) = *SWS(oldworld, x, y, ssize/2);
+ };
+ loopv(ents)
+ {
+ ents[i].x += ssize/4;
+ ents[i].y += ssize/4;
+ };
+ }
+ else
+ {
+ strn0cpy(hdr.maptitle, "Untitled Map by Unknown", 128);
+ hdr.waterlevel = -100000;
+ loopi(15) hdr.reserved[i] = 0;
+ loopk(3) loopi(256) hdr.texlists[k][i] = i;
+ ents.setsize(0);
+ block b = { 8, 8, ssize-16, ssize-16 };
+ edittypexy(SPACE, b);
+ };
+
+ calclight();
+ startmap("base/unnamed");
+ if(oldworld)
+ {
+ free(oldworld);
+ toggleedit();
+ execute("fullbright 1");
+ };
+};
+
+void mapenlarge() { empty_world(-1, false); };
+void newmap(int i) { empty_world(i, false); };
+
+COMMAND(mapenlarge, ARG_NONE);
+COMMAND(newmap, ARG_1INT);
+COMMANDN(recalc, calclight, ARG_NONE);
+COMMAND(delent, ARG_NONE);
+COMMAND(entproperty, ARG_2INT);
+
DELETED src/worldio.cpp
Index: src/worldio.cpp
==================================================================
--- src/worldio.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-// worldio.cpp: loading & saving of maps and savegames
-
-#include "cube.h"
-
-void backup(char *name, char *backupname)
-{
- remove(backupname);
- rename(name, backupname);
-};
-
-string cgzname, bakname, pcfname, mcfname;
-
-void setnames(char *name)
-{
- string pakname, mapname;
- char *slash = strpbrk(name, "/\\");
- if(slash)
- {
- strn0cpy(pakname, name, slash-name+1);
- strcpy_s(mapname, slash+1);
- }
- else
- {
- strcpy_s(pakname, "base");
- strcpy_s(mapname, name);
- };
- sprintf_s(cgzname)("packages/%s/%s.cgz", pakname, mapname);
- sprintf_s(bakname)("packages/%s/%s_%d.BAK", pakname, mapname, lastmillis);
- sprintf_s(pcfname)("packages/%s/package.cfg", pakname);
- sprintf_s(mcfname)("packages/%s/%s.cfg", pakname, mapname);
-
- path(cgzname);
- path(bakname);
-};
-
-// the optimize routines below are here to reduce the detrimental effects of messy mapping by
-// setting certain properties (vdeltas and textures) to neighbouring values wherever there is no
-// visible difference. This allows the mipmapper to generate more efficient mips.
-// the reason it is done on save is to reduce the amount spend in the mipmapper (as that is done
-// in realtime).
-
-inline bool nhf(sqr *s) { return s->type!=FHF && s->type!=CHF; };
-
-void voptimize() // reset vdeltas on non-hf cubes
-{
- loop(x, ssize) loop(y, ssize)
- {
- sqr *s = S(x, y);
- if(x && y) { if(nhf(s) && nhf(S(x-1, y)) && nhf(S(x-1, y-1)) && nhf(S(x, y-1))) s->vdelta = 0; }
- else s->vdelta = 0;
- };
-};
-
-void topt(sqr *s, bool &wf, bool &uf, int &wt, int &ut)
-{
- sqr *o[4];
- o[0] = SWS(s,0,-1,ssize);
- o[1] = SWS(s,0,1,ssize);
- o[2] = SWS(s,1,0,ssize);
- o[3] = SWS(s,-1,0,ssize);
- wf = true;
- uf = true;
- if(SOLID(s))
- {
- loopi(4) if(!SOLID(o[i]))
- {
- wf = false;
- wt = s->wtex;
- ut = s->utex;
- return;
- };
- }
- else
- {
- loopi(4) if(!SOLID(o[i]))
- {
- if(o[i]->floorfloor) { wt = s->wtex; wf = false; };
- if(o[i]->ceil>s->ceil) { ut = s->utex; uf = false; };
- };
- };
-};
-
-void toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
-{
- bool wf[4], uf[4];
- sqr *s[4];
- for(int x = 2; xwtex, ut = s[0]->utex;
- topt(s[0], wf[0], uf[0], wt, ut);
- topt(s[1] = SWS(s[0],0,1,ssize), wf[1], uf[1], wt, ut);
- topt(s[2] = SWS(s[0],1,1,ssize), wf[2], uf[2], wt, ut);
- topt(s[3] = SWS(s[0],1,0,ssize), wf[3], uf[3], wt, ut);
- loopi(4)
- {
- if(wf[i]) s[i]->wtex = wt;
- if(uf[i]) s[i]->utex = ut;
- };
- };
-};
-
-// these two are used by getmap/sendmap.. transfers compressed maps directly
-
-void writemap(char *mname, int msize, uchar *mdata)
-{
- setnames(mname);
- backup(cgzname, bakname);
- FILE *f = fopen(cgzname, "wb");
- if(!f) { conoutf("could not write map to %s", cgzname); return; };
- fwrite(mdata, 1, msize, f);
- fclose(f);
- conoutf("wrote map %s as file %s", mname, cgzname);
-}
-
-uchar *readmap(char *mname, int *msize)
-{
- setnames(mname);
- uchar *mdata = (uchar *)loadfile(cgzname, msize);
- if(!mdata) { conoutf("could not read map %s", cgzname); return NULL; };
- return mdata;
-}
-
-// save map as .cgz file. uses 2 layers of compression: first does simple run-length
-// encoding and leaves out data for certain kinds of cubes, then zlib removes the
-// last bits of redundancy. Both passes contribute greatly to the miniscule map sizes.
-
-void save_world(char *mname)
-{
- resettagareas(); // wouldn't be able to reproduce tagged areas otherwise
- voptimize();
- toptimize();
- if(!*mname) mname = getclientmap();
- setnames(mname);
- backup(cgzname, bakname);
- gzFile f = gzopen(cgzname, "wb9");
- if(!f) { conoutf("could not write map to %s", cgzname); return; };
- hdr.version = MAPVERSION;
- hdr.numents = 0;
- loopv(ents) if(ents[i].type!=NOTUSED) hdr.numents++;
- header tmp = hdr;
- endianswap(&tmp.version, sizeof(int), 4);
- endianswap(&tmp.waterlevel, sizeof(int), 16);
- gzwrite(f, &tmp, sizeof(header));
- loopv(ents)
- {
- if(ents[i].type!=NOTUSED)
- {
- entity tmp = ents[i];
- endianswap(&tmp, sizeof(short), 4);
- gzwrite(f, &tmp, sizeof(persistent_entity));
- };
- };
- sqr *t = NULL;
- int sc = 0;
- #define spurge while(sc) { gzputc(f, 255); if(sc>255) { gzputc(f, 255); sc -= 255; } else { gzputc(f, sc); sc = 0; } };
- loopk(cubicsize)
- {
- sqr *s = &world[k];
- #define c(f) (s->f==t->f)
- // 4 types of blocks, to compress a bit:
- // 255 (2): same as previous block + count
- // 254 (3): same as previous, except light // deprecated
- // SOLID (5)
- // anything else (9)
-
- if(SOLID(s))
- {
- if(t && c(type) && c(wtex) && c(vdelta))
- {
- sc++;
- }
- else
- {
- spurge;
- gzputc(f, s->type);
- gzputc(f, s->wtex);
- gzputc(f, s->vdelta);
- };
- }
- else
- {
- if(t && c(type) && c(floor) && c(ceil) && c(ctex) && c(ftex) && c(utex) && c(wtex) && c(vdelta) && c(tag))
- {
- sc++;
- }
- else
- {
- spurge;
- gzputc(f, s->type);
- gzputc(f, s->floor);
- gzputc(f, s->ceil);
- gzputc(f, s->wtex);
- gzputc(f, s->ftex);
- gzputc(f, s->ctex);
- gzputc(f, s->vdelta);
- gzputc(f, s->utex);
- gzputc(f, s->tag);
- };
- };
- t = s;
- };
- spurge;
- gzclose(f);
- conoutf("wrote map file %s", cgzname);
- settagareas();
-};
-
-void load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas!
-{
- stopifrecording();
- cleardlights();
- pruneundos();
- setnames(mname);
- gzFile f = gzopen(cgzname, "rb9");
- if(!f) { conoutf("could not read map %s", cgzname); return; };
- gzread(f, &hdr, sizeof(header)-sizeof(int)*16);
- endianswap(&hdr.version, sizeof(int), 4);
- if(strncmp(hdr.head, "CUBE", 4)!=0) fatal("while reading map: header malformatted");
- if(hdr.version>MAPVERSION) fatal("this map requires a newer version of cube");
- if(sfactorLARGEST_FACTOR) fatal("illegal map size");
- if(hdr.version>=4)
- {
- gzread(f, &hdr.waterlevel, sizeof(int)*16);
- endianswap(&hdr.waterlevel, sizeof(int), 16);
- }
- else
- {
- hdr.waterlevel = -100000;
- };
- ents.setsize(0);
- loopi(hdr.numents)
- {
- entity &e = ents.add();
- gzread(f, &e, sizeof(persistent_entity));
- endianswap(&e, sizeof(short), 4);
- e.spawned = false;
- if(e.type==LIGHT)
- {
- if(!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2
- if(e.attr1>32) e.attr1 = 32; // 12_03 and below
- };
- };
- free(world);
- setupworld(hdr.sfactor);
- char texuse[256];
- loopi(256) texuse[i] = 0;
- sqr *t = NULL;
- loopk(cubicsize)
- {
- sqr *s = &world[k];
- int type = gzgetc(f);
- switch(type)
- {
- case 255:
- {
- int n = gzgetc(f);
- for(int i = 0; ir = s->g = s->b = gzgetc(f);
- gzgetc(f);
- break;
- };
- case SOLID:
- {
- s->type = SOLID;
- s->wtex = gzgetc(f);
- s->vdelta = gzgetc(f);
- if(hdr.version<=2) { gzgetc(f); gzgetc(f); };
- s->ftex = DEFAULT_FLOOR;
- s->ctex = DEFAULT_CEIL;
- s->utex = s->wtex;
- s->tag = 0;
- s->floor = 0;
- s->ceil = 16;
- break;
- };
- default:
- {
- if(type<0 || type>=MAXTYPE)
- {
- sprintf_sd(t)("%d @ %d", type, k);
- fatal("while reading map: type out of range: ", t);
- };
- s->type = type;
- s->floor = gzgetc(f);
- s->ceil = gzgetc(f);
- if(s->floor>=s->ceil) s->floor = s->ceil-1; // for pre 12_13
- s->wtex = gzgetc(f);
- s->ftex = gzgetc(f);
- s->ctex = gzgetc(f);
- if(hdr.version<=2) { gzgetc(f); gzgetc(f); };
- s->vdelta = gzgetc(f);
- s->utex = (hdr.version>=2) ? gzgetc(f) : s->wtex;
- s->tag = (hdr.version>=5) ? gzgetc(f) : 0;
- s->type = type;
- };
- };
- s->defer = 0;
- t = s;
- texuse[s->wtex] = 1;
- if(!SOLID(s)) texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1;
- };
- gzclose(f);
- calclight();
- settagareas();
- int xs, ys;
- loopi(256) if(texuse) lookuptexture(i, xs, ys);
- conoutf("read map %s (%d milliseconds)", cgzname, SDL_GetTicks()-lastmillis);
- conoutf("%s", hdr.maptitle);
- startmap(mname);
- loopl(256)
- {
- sprintf_sd(aliasname)("level_trigger_%d", l); // can this be done smarter?
- if(identexists(aliasname)) alias(aliasname, "");
- };
- execfile("data/default_map_settings.cfg");
- execfile(pcfname);
- execfile(mcfname);
-};
-
-COMMANDN(savemap, save_world, ARG_1STR);
-
ADDED src/worldio.cxx
Index: src/worldio.cxx
==================================================================
--- /dev/null
+++ src/worldio.cxx
@@ -0,0 +1,328 @@
+// worldio.cpp: loading & saving of maps and savegames
+
+#include "cube.h"
+
+void backup(char *name, char *backupname)
+{
+ remove(backupname);
+ rename(name, backupname);
+};
+
+string cgzname, bakname, pcfname, mcfname;
+
+void setnames(char *name)
+{
+ string pakname, mapname;
+ char *slash = strpbrk(name, "/\\");
+ if(slash)
+ {
+ strn0cpy(pakname, name, slash-name+1);
+ strcpy_s(mapname, slash+1);
+ }
+ else
+ {
+ strcpy_s(pakname, "base");
+ strcpy_s(mapname, name);
+ };
+ sprintf_s(cgzname)("packages/%s/%s.cgz", pakname, mapname);
+ sprintf_s(bakname)("packages/%s/%s_%d.BAK", pakname, mapname, lastmillis);
+ sprintf_s(pcfname)("packages/%s/package.cfg", pakname);
+ sprintf_s(mcfname)("packages/%s/%s.cfg", pakname, mapname);
+
+ path(cgzname);
+ path(bakname);
+};
+
+// the optimize routines below are here to reduce the detrimental effects of messy mapping by
+// setting certain properties (vdeltas and textures) to neighbouring values wherever there is no
+// visible difference. This allows the mipmapper to generate more efficient mips.
+// the reason it is done on save is to reduce the amount spend in the mipmapper (as that is done
+// in realtime).
+
+inline bool nhf(sqr *s) { return s->type!=FHF && s->type!=CHF; };
+
+void voptimize() // reset vdeltas on non-hf cubes
+{
+ loop(x, ssize) loop(y, ssize)
+ {
+ sqr *s = S(x, y);
+ if(x && y) { if(nhf(s) && nhf(S(x-1, y)) && nhf(S(x-1, y-1)) && nhf(S(x, y-1))) s->vdelta = 0; }
+ else s->vdelta = 0;
+ };
+};
+
+void topt(sqr *s, bool &wf, bool &uf, int &wt, int &ut)
+{
+ sqr *o[4];
+ o[0] = SWS(s,0,-1,ssize);
+ o[1] = SWS(s,0,1,ssize);
+ o[2] = SWS(s,1,0,ssize);
+ o[3] = SWS(s,-1,0,ssize);
+ wf = true;
+ uf = true;
+ if(SOLID(s))
+ {
+ loopi(4) if(!SOLID(o[i]))
+ {
+ wf = false;
+ wt = s->wtex;
+ ut = s->utex;
+ return;
+ };
+ }
+ else
+ {
+ loopi(4) if(!SOLID(o[i]))
+ {
+ if(o[i]->floorfloor) { wt = s->wtex; wf = false; };
+ if(o[i]->ceil>s->ceil) { ut = s->utex; uf = false; };
+ };
+ };
+};
+
+void toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
+{
+ bool wf[4], uf[4];
+ sqr *s[4];
+ for(int x = 2; xwtex, ut = s[0]->utex;
+ topt(s[0], wf[0], uf[0], wt, ut);
+ topt(s[1] = SWS(s[0],0,1,ssize), wf[1], uf[1], wt, ut);
+ topt(s[2] = SWS(s[0],1,1,ssize), wf[2], uf[2], wt, ut);
+ topt(s[3] = SWS(s[0],1,0,ssize), wf[3], uf[3], wt, ut);
+ loopi(4)
+ {
+ if(wf[i]) s[i]->wtex = wt;
+ if(uf[i]) s[i]->utex = ut;
+ };
+ };
+};
+
+// these two are used by getmap/sendmap.. transfers compressed maps directly
+
+void writemap(char *mname, int msize, uchar *mdata)
+{
+ setnames(mname);
+ backup(cgzname, bakname);
+ FILE *f = fopen(cgzname, "wb");
+ if(!f) { conoutf("could not write map to %s", cgzname); return; };
+ fwrite(mdata, 1, msize, f);
+ fclose(f);
+ conoutf("wrote map %s as file %s", mname, cgzname);
+}
+
+uchar *readmap(char *mname, int *msize)
+{
+ setnames(mname);
+ uchar *mdata = (uchar *)loadfile(cgzname, msize);
+ if(!mdata) { conoutf("could not read map %s", cgzname); return NULL; };
+ return mdata;
+}
+
+// save map as .cgz file. uses 2 layers of compression: first does simple run-length
+// encoding and leaves out data for certain kinds of cubes, then zlib removes the
+// last bits of redundancy. Both passes contribute greatly to the miniscule map sizes.
+
+void save_world(char *mname)
+{
+ resettagareas(); // wouldn't be able to reproduce tagged areas otherwise
+ voptimize();
+ toptimize();
+ if(!*mname) mname = getclientmap();
+ setnames(mname);
+ backup(cgzname, bakname);
+ gzFile f = gzopen(cgzname, "wb9");
+ if(!f) { conoutf("could not write map to %s", cgzname); return; };
+ hdr.version = MAPVERSION;
+ hdr.numents = 0;
+ loopv(ents) if(ents[i].type!=NOTUSED) hdr.numents++;
+ header tmp = hdr;
+ endianswap(&tmp.version, sizeof(int), 4);
+ endianswap(&tmp.waterlevel, sizeof(int), 16);
+ gzwrite(f, &tmp, sizeof(header));
+ loopv(ents)
+ {
+ if(ents[i].type!=NOTUSED)
+ {
+ entity tmp = ents[i];
+ endianswap(&tmp, sizeof(short), 4);
+ gzwrite(f, &tmp, sizeof(persistent_entity));
+ };
+ };
+ sqr *t = NULL;
+ int sc = 0;
+ #define spurge while(sc) { gzputc(f, 255); if(sc>255) { gzputc(f, 255); sc -= 255; } else { gzputc(f, sc); sc = 0; } };
+ loopk(cubicsize)
+ {
+ sqr *s = &world[k];
+ #define c(f) (s->f==t->f)
+ // 4 types of blocks, to compress a bit:
+ // 255 (2): same as previous block + count
+ // 254 (3): same as previous, except light // deprecated
+ // SOLID (5)
+ // anything else (9)
+
+ if(SOLID(s))
+ {
+ if(t && c(type) && c(wtex) && c(vdelta))
+ {
+ sc++;
+ }
+ else
+ {
+ spurge;
+ gzputc(f, s->type);
+ gzputc(f, s->wtex);
+ gzputc(f, s->vdelta);
+ };
+ }
+ else
+ {
+ if(t && c(type) && c(floor) && c(ceil) && c(ctex) && c(ftex) && c(utex) && c(wtex) && c(vdelta) && c(tag))
+ {
+ sc++;
+ }
+ else
+ {
+ spurge;
+ gzputc(f, s->type);
+ gzputc(f, s->floor);
+ gzputc(f, s->ceil);
+ gzputc(f, s->wtex);
+ gzputc(f, s->ftex);
+ gzputc(f, s->ctex);
+ gzputc(f, s->vdelta);
+ gzputc(f, s->utex);
+ gzputc(f, s->tag);
+ };
+ };
+ t = s;
+ };
+ spurge;
+ gzclose(f);
+ conoutf("wrote map file %s", cgzname);
+ settagareas();
+};
+
+void load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas!
+{
+ stopifrecording();
+ cleardlights();
+ pruneundos();
+ setnames(mname);
+ gzFile f = gzopen(cgzname, "rb9");
+ if(!f) { conoutf("could not read map %s", cgzname); return; };
+ gzread(f, &hdr, sizeof(header)-sizeof(int)*16);
+ endianswap(&hdr.version, sizeof(int), 4);
+ if(strncmp(hdr.head, "CUBE", 4)!=0) fatal("while reading map: header malformatted");
+ if(hdr.version>MAPVERSION) fatal("this map requires a newer version of cube");
+ if(sfactorLARGEST_FACTOR) fatal("illegal map size");
+ if(hdr.version>=4)
+ {
+ gzread(f, &hdr.waterlevel, sizeof(int)*16);
+ endianswap(&hdr.waterlevel, sizeof(int), 16);
+ }
+ else
+ {
+ hdr.waterlevel = -100000;
+ };
+ ents.setsize(0);
+ loopi(hdr.numents)
+ {
+ entity &e = ents.add();
+ gzread(f, &e, sizeof(persistent_entity));
+ endianswap(&e, sizeof(short), 4);
+ e.spawned = false;
+ if(e.type==LIGHT)
+ {
+ if(!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2
+ if(e.attr1>32) e.attr1 = 32; // 12_03 and below
+ };
+ };
+ free(world);
+ setupworld(hdr.sfactor);
+ char texuse[256];
+ loopi(256) texuse[i] = 0;
+ sqr *t = NULL;
+ loopk(cubicsize)
+ {
+ sqr *s = &world[k];
+ int type = gzgetc(f);
+ switch(type)
+ {
+ case 255:
+ {
+ int n = gzgetc(f);
+ for(int i = 0; ir = s->g = s->b = gzgetc(f);
+ gzgetc(f);
+ break;
+ };
+ case SOLID:
+ {
+ s->type = SOLID;
+ s->wtex = gzgetc(f);
+ s->vdelta = gzgetc(f);
+ if(hdr.version<=2) { gzgetc(f); gzgetc(f); };
+ s->ftex = DEFAULT_FLOOR;
+ s->ctex = DEFAULT_CEIL;
+ s->utex = s->wtex;
+ s->tag = 0;
+ s->floor = 0;
+ s->ceil = 16;
+ break;
+ };
+ default:
+ {
+ if(type<0 || type>=MAXTYPE)
+ {
+ sprintf_sd(t)("%d @ %d", type, k);
+ fatal("while reading map: type out of range: ", t);
+ };
+ s->type = type;
+ s->floor = gzgetc(f);
+ s->ceil = gzgetc(f);
+ if(s->floor>=s->ceil) s->floor = s->ceil-1; // for pre 12_13
+ s->wtex = gzgetc(f);
+ s->ftex = gzgetc(f);
+ s->ctex = gzgetc(f);
+ if(hdr.version<=2) { gzgetc(f); gzgetc(f); };
+ s->vdelta = gzgetc(f);
+ s->utex = (hdr.version>=2) ? gzgetc(f) : s->wtex;
+ s->tag = (hdr.version>=5) ? gzgetc(f) : 0;
+ s->type = type;
+ };
+ };
+ s->defer = 0;
+ t = s;
+ texuse[s->wtex] = 1;
+ if(!SOLID(s)) texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1;
+ };
+ gzclose(f);
+ calclight();
+ settagareas();
+ int xs, ys;
+ loopi(256) if(texuse) lookuptexture(i, xs, ys);
+ conoutf("read map %s (%d milliseconds)", cgzname, SDL_GetTicks()-lastmillis);
+ conoutf("%s", hdr.maptitle);
+ startmap(mname);
+ loopl(256)
+ {
+ sprintf_sd(aliasname)("level_trigger_%d", l); // can this be done smarter?
+ if(identexists(aliasname)) alias(aliasname, "");
+ };
+ execfile("data/default_map_settings.cfg");
+ execfile(pcfname);
+ execfile(mcfname);
+};
+
+COMMANDN(savemap, save_world, ARG_1STR);
+
DELETED src/worldlight.cpp
Index: src/worldlight.cpp
==================================================================
--- src/worldlight.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-// worldlight.cpp
-
-#include "cube.h"
-
-extern bool hasoverbright;
-
-VAR(lightscale,1,4,100);
-
-void lightray(float bx, float by, persistent_entity &light) // done in realtime, needs to be fast
-{
- float lx = light.x+(rnd(21)-10)*0.1f;
- float ly = light.y+(rnd(21)-10)*0.1f;
- float dx = bx-lx;
- float dy = by-ly;
- float dist = (float)sqrt(dx*dx+dy*dy);
- if(dist<1.0f) return;
- int reach = light.attr1;
- int steps = (int)(reach*reach*1.6f/dist); // can change this for speedup/quality?
- const int PRECBITS = 12;
- const float PRECF = 4096.0f;
- int x = (int)(lx*PRECF);
- int y = (int)(ly*PRECF);
- int l = light.attr2<>PRECBITS, y>>PRECBITS)) return;
-
- int g = light.attr3<>PRECBITS, y>>PRECBITS);
- int tl = (l>>PRECBITS)+s->r;
- s->r = tl>255 ? 255 : tl;
- tl = (g>>PRECBITS)+s->g;
- s->g = tl>255 ? 255 : tl;
- tl = (b>>PRECBITS)+s->b;
- s->b = tl>255 ? 255 : tl;
- if(SOLID(s)) return;
- x += stepx;
- y += stepy;
- l -= stepl;
- g -= stepg;
- b -= stepb;
- stepl -= 25;
- stepg -= 25;
- stepb -= 25;
- };
- }
- else // white light, special optimized version
- {
- int dimness = rnd((255-light.attr2)/16+1);
- x += stepx*dimness;
- y += stepy*dimness;
-
- if(OUTBORD(x>>PRECBITS, y>>PRECBITS)) return;
-
- loopi(steps)
- {
- sqr *s = S(x>>PRECBITS, y>>PRECBITS);
- int tl = (l>>PRECBITS)+s->r;
- s->r = s->g = s->b = tl>255 ? 255 : tl;
- if(SOLID(s)) return;
- x += stepx;
- y += stepy;
- l -= stepl;
- stepl -= 25;
- };
- };
- }
- else // the old (white) light code, here for the few people with old video cards that don't support overbright
- {
- loopi(steps)
- {
- sqr *s = S(x>>PRECBITS, y>>PRECBITS);
- int light = l>>PRECBITS;
- if(light>s->r) s->r = s->g = s->b = (uchar)light;
- if(SOLID(s)) return;
- x += stepx;
- y += stepy;
- l -= stepl;
- };
- };
-
-};
-
-void calclightsource(persistent_entity &l)
-{
- int reach = l.attr1;
- int sx = l.x-reach;
- int ex = l.x+reach;
- int sy = l.y-reach;
- int ey = l.y+reach;
-
- rndreset();
-
- const float s = 0.8f;
-
- for(float sx2 = (float)sx; sx2<=ex; sx2+=s*2) { lightray(sx2, (float)sy, l); lightray(sx2, (float)ey, l); };
- for(float sy2 = sy+s; sy2<=ey-s; sy2+=s*2) { lightray((float)sx, sy2, l); lightray((float)ex, sy2, l); };
-
- rndtime();
-};
-
-void postlightarea(block &a) // median filter, smooths out random noise in light and makes it more mipable
-{
- loop(x,a.xs) loop(y,a.ys) // assumes area not on edge of world
- {
- sqr *s = S(x+a.x,y+a.y);
- #define median(m) s->m = (s->m*2 + SW(s,1,0)->m*2 + SW(s,0,1)->m*2 \
- + SW(s,-1,0)->m*2 + SW(s,0,-1)->m*2 \
- + SW(s,1,1)->m + SW(s,1,-1)->m \
- + SW(s,-1,1)->m + SW(s,-1,-1)->m)/14; // median is 4/2/1 instead
- median(r);
- median(g);
- median(b);
- };
-
- remip(a);
-};
-
-void calclight()
-{
- loop(x,ssize) loop(y,ssize)
- {
- sqr *s = S(x,y);
- s->r = s->g = s->b = 10;
- };
-
- loopv(ents)
- {
- entity &e = ents[i];
- if(e.type==LIGHT) calclightsource(e);
- };
-
- block b = { 1, 1, ssize-2, ssize-2 };
- postlightarea(b);
- setvar("fullbright", 0);
-};
-
-VARP(dynlight, 0, 16, 32);
-
-vector dlights;
-
-void cleardlights()
-{
- while(!dlights.empty())
- {
- block *backup = dlights.pop();
- blockpaste(*backup);
- free(backup);
- };
-};
-
-void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner)
-{
- if(!reach) reach = dynlight;
- if(owner->monsterstate) reach = reach/2;
- if(!reach) return;
- if(v.x<0 || v.y<0 || v.x>ssize || v.y>ssize) return;
-
- int creach = reach+16; // dependant on lightray random offsets!
- block b = { (int)v.x-creach, (int)v.y-creach, creach*2+1, creach*2+1 };
-
- if(b.x<1) b.x = 1;
- if(b.y<1) b.y = 1;
- if(b.xs+b.x>ssize-2) b.xs = ssize-2-b.x;
- if(b.ys+b.y>ssize-2) b.ys = ssize-2-b.y;
-
- dlights.add(blockcopy(b)); // backup area before rendering in dynlight
-
- persistent_entity l = { (int)v.x, (int)v.y, (int)v.z, reach, LIGHT, strength, 0, 0 };
- calclightsource(l);
- postlightarea(b);
-};
-
-// utility functions also used by editing code
-
-block *blockcopy(block &s)
-{
- block *b = (block *)alloc(sizeof(block)+s.xs*s.ys*sizeof(sqr));
- *b = s;
- sqr *q = (sqr *)(b+1);
- for(int x = s.x; x>PRECBITS, y>>PRECBITS)) return;
+
+ int g = light.attr3<>PRECBITS, y>>PRECBITS);
+ int tl = (l>>PRECBITS)+s->r;
+ s->r = tl>255 ? 255 : tl;
+ tl = (g>>PRECBITS)+s->g;
+ s->g = tl>255 ? 255 : tl;
+ tl = (b>>PRECBITS)+s->b;
+ s->b = tl>255 ? 255 : tl;
+ if(SOLID(s)) return;
+ x += stepx;
+ y += stepy;
+ l -= stepl;
+ g -= stepg;
+ b -= stepb;
+ stepl -= 25;
+ stepg -= 25;
+ stepb -= 25;
+ };
+ }
+ else // white light, special optimized version
+ {
+ int dimness = rnd((255-light.attr2)/16+1);
+ x += stepx*dimness;
+ y += stepy*dimness;
+
+ if(OUTBORD(x>>PRECBITS, y>>PRECBITS)) return;
+
+ loopi(steps)
+ {
+ sqr *s = S(x>>PRECBITS, y>>PRECBITS);
+ int tl = (l>>PRECBITS)+s->r;
+ s->r = s->g = s->b = tl>255 ? 255 : tl;
+ if(SOLID(s)) return;
+ x += stepx;
+ y += stepy;
+ l -= stepl;
+ stepl -= 25;
+ };
+ };
+ }
+ else // the old (white) light code, here for the few people with old video cards that don't support overbright
+ {
+ loopi(steps)
+ {
+ sqr *s = S(x>>PRECBITS, y>>PRECBITS);
+ int light = l>>PRECBITS;
+ if(light>s->r) s->r = s->g = s->b = (uchar)light;
+ if(SOLID(s)) return;
+ x += stepx;
+ y += stepy;
+ l -= stepl;
+ };
+ };
+
+};
+
+void calclightsource(persistent_entity &l)
+{
+ int reach = l.attr1;
+ int sx = l.x-reach;
+ int ex = l.x+reach;
+ int sy = l.y-reach;
+ int ey = l.y+reach;
+
+ rndreset();
+
+ const float s = 0.8f;
+
+ for(float sx2 = (float)sx; sx2<=ex; sx2+=s*2) { lightray(sx2, (float)sy, l); lightray(sx2, (float)ey, l); };
+ for(float sy2 = sy+s; sy2<=ey-s; sy2+=s*2) { lightray((float)sx, sy2, l); lightray((float)ex, sy2, l); };
+
+ rndtime();
+};
+
+void postlightarea(block &a) // median filter, smooths out random noise in light and makes it more mipable
+{
+ loop(x,a.xs) loop(y,a.ys) // assumes area not on edge of world
+ {
+ sqr *s = S(x+a.x,y+a.y);
+ #define median(m) s->m = (s->m*2 + SW(s,1,0)->m*2 + SW(s,0,1)->m*2 \
+ + SW(s,-1,0)->m*2 + SW(s,0,-1)->m*2 \
+ + SW(s,1,1)->m + SW(s,1,-1)->m \
+ + SW(s,-1,1)->m + SW(s,-1,-1)->m)/14; // median is 4/2/1 instead
+ median(r);
+ median(g);
+ median(b);
+ };
+
+ remip(a);
+};
+
+void calclight()
+{
+ loop(x,ssize) loop(y,ssize)
+ {
+ sqr *s = S(x,y);
+ s->r = s->g = s->b = 10;
+ };
+
+ loopv(ents)
+ {
+ entity &e = ents[i];
+ if(e.type==LIGHT) calclightsource(e);
+ };
+
+ block b = { 1, 1, ssize-2, ssize-2 };
+ postlightarea(b);
+ setvar("fullbright", 0);
+};
+
+VARP(dynlight, 0, 16, 32);
+
+vector dlights;
+
+void cleardlights()
+{
+ while(!dlights.empty())
+ {
+ block *backup = dlights.pop();
+ blockpaste(*backup);
+ free(backup);
+ };
+};
+
+void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner)
+{
+ if(!reach) reach = dynlight;
+ if(owner->monsterstate) reach = reach/2;
+ if(!reach) return;
+ if(v.x<0 || v.y<0 || v.x>ssize || v.y>ssize) return;
+
+ int creach = reach+16; // dependant on lightray random offsets!
+ block b = { (int)v.x-creach, (int)v.y-creach, creach*2+1, creach*2+1 };
+
+ if(b.x<1) b.x = 1;
+ if(b.y<1) b.y = 1;
+ if(b.xs+b.x>ssize-2) b.xs = ssize-2-b.x;
+ if(b.ys+b.y>ssize-2) b.ys = ssize-2-b.y;
+
+ dlights.add(blockcopy(b)); // backup area before rendering in dynlight
+
+ persistent_entity l = { (int)v.x, (int)v.y, (int)v.z, reach, LIGHT, strength, 0, 0 };
+ calclightsource(l);
+ postlightarea(b);
+};
+
+// utility functions also used by editing code
+
+block *blockcopy(block &s)
+{
+ block *b = (block *)alloc(sizeof(block)+s.xs*s.ys*sizeof(sqr));
+ *b = s;
+ sqr *q = (sqr *)(b+1);
+ for(int x = s.x; xpitch);
- float af = getvar("fov")/2+apitch/1.5f+3;
- float byaw = (player1->yaw-90+af)/360*PI2;
- float syaw = (player1->yaw-90-af)/360*PI2;
-
- loopi(NUMRAYS)
- {
- float angle = i*PI2/NUMRAYS;
- if((apitch>45 // must be bigger if fov>120
- || (anglesyaw)
- || (anglesyaw-PI2)
- || (anglesyaw+PI2))
- && !OUTBORD(vx, vy)
- && !SOLID(S(fast_f2nat(vx), fast_f2nat(vy)))) // try to avoid tracing ray if outside of frustrum
- {
- float ray = i*8/(float)NUMRAYS;
- float dx, dy;
- if(ray>1 && ray<3) { dx = -(ray-2); dy = 1; }
- else if(ray>=3 && ray<5) { dx = -1; dy = -(ray-4); }
- else if(ray>=5 && ray<7) { dx = ray-6; dy = -1; }
- else { dx = 1; dy = ray>4 ? ray-8 : ray; };
- float sx = vx;
- float sy = vy;
- for(;;)
- {
- sx += dx;
- sy += dy;
- if(SOLID(S(fast_f2nat(sx), fast_f2nat(sy)))) // 90% of time spend in this function is on this line
- {
- rdist[i] = (float)(fabs(sx-vx)+fabs(sy-vy));
- break;
- };
- };
- }
- else
- {
- rdist[i] = 2;
- };
- };
-};
-
-// test occlusion for a cube... one of the most computationally expensive functions in the engine
-// as its done for every cube and entity, but its effect is more than worth it!
-
-inline float ca(float x, float y) { return x>y ? y/x : 2-x/y; };
-inline float ma(float x, float y) { return x==0 ? (y>0 ? 2 : -2) : y/x; };
-
-int isoccluded(float vx, float vy, float cx, float cy, float csize) // v = viewer, c = cube to test
-{
- if(!ocull) return 0;
-
- float nx = vx, ny = vy; // n = point on the border of the cube that is closest to v
- if(nxcx+csize) nx = cx+csize;
- if(nycy+csize) ny = cy+csize;
- float xdist = (float)fabs(nx-vx);
- float ydist = (float)fabs(ny-vy);
- if(xdist>odist || ydist>odist) return 2;
- float dist = xdist+ydist-1; // 1 needed?
-
- // ABC
- // D E
- // FGH
-
- // - check middle cube? BG
-
- // find highest and lowest angle in the occlusion map that this cube spans, based on its most left and right
- // points on the border from the viewer pov... I see no easier way to do this than this silly code below
-
- float h, l;
- if(cx<=vx) // ABDFG
- {
- if(cx+csizepitch);
+ float af = getvar("fov")/2+apitch/1.5f+3;
+ float byaw = (player1->yaw-90+af)/360*PI2;
+ float syaw = (player1->yaw-90-af)/360*PI2;
+
+ loopi(NUMRAYS)
+ {
+ float angle = i*PI2/NUMRAYS;
+ if((apitch>45 // must be bigger if fov>120
+ || (anglesyaw)
+ || (anglesyaw-PI2)
+ || (anglesyaw+PI2))
+ && !OUTBORD(vx, vy)
+ && !SOLID(S(fast_f2nat(vx), fast_f2nat(vy)))) // try to avoid tracing ray if outside of frustrum
+ {
+ float ray = i*8/(float)NUMRAYS;
+ float dx, dy;
+ if(ray>1 && ray<3) { dx = -(ray-2); dy = 1; }
+ else if(ray>=3 && ray<5) { dx = -1; dy = -(ray-4); }
+ else if(ray>=5 && ray<7) { dx = ray-6; dy = -1; }
+ else { dx = 1; dy = ray>4 ? ray-8 : ray; };
+ float sx = vx;
+ float sy = vy;
+ for(;;)
+ {
+ sx += dx;
+ sy += dy;
+ if(SOLID(S(fast_f2nat(sx), fast_f2nat(sy)))) // 90% of time spend in this function is on this line
+ {
+ rdist[i] = (float)(fabs(sx-vx)+fabs(sy-vy));
+ break;
+ };
+ };
+ }
+ else
+ {
+ rdist[i] = 2;
+ };
+ };
+};
+
+// test occlusion for a cube... one of the most computationally expensive functions in the engine
+// as its done for every cube and entity, but its effect is more than worth it!
+
+inline float ca(float x, float y) { return x>y ? y/x : 2-x/y; };
+inline float ma(float x, float y) { return x==0 ? (y>0 ? 2 : -2) : y/x; };
+
+int isoccluded(float vx, float vy, float cx, float cy, float csize) // v = viewer, c = cube to test
+{
+ if(!ocull) return 0;
+
+ float nx = vx, ny = vy; // n = point on the border of the cube that is closest to v
+ if(nxcx+csize) nx = cx+csize;
+ if(nycy+csize) ny = cy+csize;
+ float xdist = (float)fabs(nx-vx);
+ float ydist = (float)fabs(ny-vy);
+ if(xdist>odist || ydist>odist) return 2;
+ float dist = xdist+ydist-1; // 1 needed?
+
+ // ABC
+ // D E
+ // FGH
+
+ // - check middle cube? BG
+
+ // find highest and lowest angle in the occlusion map that this cube spans, based on its most left and right
+ // points on the border from the viewer pov... I see no easier way to do this than this silly code below
+
+ float h, l;
+ if(cx<=vx) // ABDFG
+ {
+ if(cx+csizetype==SEMISOLID)
- {
- float c1 = s->floor;
- float c2 = s->floor;
- if(s->type==FHF) { c1 -= d1->vdelta/4.0f; c2 -= d2->vdelta/4.0f; };
- float f1 = s->ceil;
- float f2 = s->ceil;
- if(s->type==CHF) { f1 += d1->vdelta/4.0f; f2 += d2->vdelta/4.0f; };
- //if(f1-c1<=0 && f2-c2<=0) return;
- render_square(o->wtex, c1, c2, f1, f2, x1<floor;
- float f2 = s->floor;
- float c1 = o->floor;
- float c2 = o->floor;
- if(o->type==FHF && s->type!=FHF)
- {
- c1 -= d1->vdelta/4.0f;
- c2 -= d2->vdelta/4.0f;
- }
- if(s->type==FHF && o->type!=FHF)
- {
- f1 -= d1->vdelta/4.0f;
- f2 -= d2->vdelta/4.0f;
- }
- if(f1>=c1 && f2>=c2) goto skip;
- render_square(o->wtex, f1, f2, c1, c2, x1<ceil;
- float f2 = o->ceil;
- float c1 = s->ceil;
- float c2 = s->ceil;
- if(o->type==CHF && s->type!=CHF)
- {
- f1 += d1->vdelta/4.0f;
- f2 += d2->vdelta/4.0f;
- }
- else if(s->type==CHF && o->type!=CHF)
- {
- c1 += d1->vdelta/4.0f;
- c2 += d2->vdelta/4.0f;
- }
- if(c1<=f1 && c2<=f2) return;
- render_square(o->utex, f1, f2, c1, c2, x1<>mip;
- x *= 2;
- y *= 2;
- switch(SWS(w, x+x1, y+y1, msize)->type)
- {
- case SEMISOLID: if(issemi(mip, x+x1, y+y1, x1, y1, x2, y2)) return true;
- case CORNER:
- case SOLID: break;
- default: return true;
- };
- switch(SWS(w, x+x2, y+y2, msize)->type)
- {
- case SEMISOLID: if(issemi(mip, x+x2, y+y2, x1, y1, x2, y2)) return true;
- case CORNER:
- case SOLID: break;
- default: return true;
- };
- return false;
-};
-
-bool render_floor, render_ceil;
-
-// the core recursive function, renders a rect of cubes at a certain mip level from a viewer perspective
-// call itself for lower mip levels, on most modern machines however this function will use the higher
-// mip levels only for perfect mips.
-
-void render_seg_new(float vx, float vy, float vh, int mip, int x, int y, int xs, int ys)
-{
- sqr *w = wmip[mip];
- int sz = ssize>>mip;
- int vxx = ((int)vx+(1<>mip;
- int vyy = ((int)vy+(1<>mip;
- int lx = vxx-lodleft; // these mark the rect inside the current rest that we want to render using a lower mip level
- int ly = vyy-lodtop;
- int rx = vxx+lodright;
- int ry = vyy+lodbot;
-
- float fsize = (float)(1<occluded = isoccluded(player1->o.x, player1->o.y, (float)(ox<>mip;
- int pvy = (int)vy>>mip;
- if(pvx>=0 && pvy>=0 && pvxoccluded = 0;
- SWS(w, pvx, pvy, sz)->occluded = 0; // player cell never occluded
- };
-
- #define df(x) s->floor-(x->vdelta/4.0f)
- #define dc(x) s->ceil+(x->vdelta/4.0f)
-
- // loop through the rect 3 times (for floor/ceil/walls seperately, to facilitate dynamic stripify)
- // for each we skip occluded cubes (occlusion at higher mip levels is a big time saver!).
- // during the first loop (ceil) we collect cubes that lie within the lower mip rect and are
- // also deferred, and render them recursively. Anything left (perfect mips and higher lods) we
- // render here.
-
- #define LOOPH {for(int xx = x; xxoccluded==1) continue; \
- if(s->defer && !s->occluded && mip && xx>=lx && xx=ly && yy